David Harris's Technology Blog

ColdFusion, Flex, and other stuff...   (and 338,195 hours, 40 mins in to my plan for global domination)

Search:

Calendar:

Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Subscribe:

Enter your email address to subscribe to this blog.

Archives By Subject:

Tags:

action script adobe air ajax cfug coldfusion flash flex frameworks free software fxug general jpgmetadatareader mac off topic opensource papervision spry

Recent Entries:

No recent entries.

Top Posts:

Recent Comments:

Top Commenters:

My Links:

RSS:


Answering "evaluate()"'s cry for help

Mark Ireland's blog post is-eval()-a-cry-for-help? caught my interest earlier today.

I don't normally do blog entries on other people blog entries, but this one got me thinking...

In his example he was asking if one code example was better or worse than another.

Times when I start convincing myself that I may need to use the "evaluate" function, I normally take a step back, look at the code and then work out a more elegant way to execute the code.

evaluate in it's self is not the end of the world, but the consistent use of it introduces overhead that can often be avoided. (a quick google search on "ColdFusion evaluate" shows multiple hits on how not to use it)

Peter Bell, an active and respected member of the CF community added this comment:

[quote]

You can *almost* always remove evaluate, but one case I keep running into is this.

I have a generic getter that calls a custom getter if it exists. If needs to call variables.get#PropertyName#().

I have to do:

ReturnValue = evaluate("variables.get#arguments.PropertyName#()");

because variables["get" & PropertyName]() isn't syntactically valid CF for some reason.

[/quote]

Here is one way to not use evaluate in that situation:

<cfset fFunction = variables["get#arguments.PropertyName#"]>
<cfset returnValue = fFunction()>

The ability in ColdFusion assign functions to values, then call that value is pretty cool. From my limited understanding, that is heading down the "Mixin" track.

You could declare a structure, and get functions from multiple CFCs and assign them to keys in that structure...

...when I start thinking about this, for some reason Frankenstein's CFC pops in to my head ...wonder why?

Related Blog Entries

Comments
Hi David,

First off, many thanks for the suggestion - it works out perfectly! In my case this wasn't to implement mixins (although I use them elsewhere), but just to allow the calling of methods where the method name is determined dynamically.

Allows me to do stuff like
addMethod("GetAllUsers", "MethodType:getByFIlter|Filter:1=1|PropertyNameList:FirstName,LastName|Order:LastName, FirstName|");

then I can call("GetAllUsers") and I have me a method I don't actually need to code. useful for all of those little methods which really just parameterize more basic methods.

Thanks again for the solution to removing the evaluation!
# Posted By Peter Bell | 4/19/07 4:11 AM
Glad to help!
Thanks for the more detailed explanation of what you are doing. I was a bit confused at first why you would call a dynamic "getProperty" function to call a static "getProperty" function, but now that makes sense! :-)
# Posted By David Harris | 4/19/07 7:21 AM
Well, that was another place. The idea is you want generic getters otherwise you have to create a getter for every property - even with passive code gen, not nice as you have thousands of lines of boilerplate to maintain.

I have generic getter so you can Product.get("Title"), but what happens if you want the Title to be calculated? Well then you add a getTitle() method to property. But then you are not encapsulating changes as the calling templates wuld have to change from get("Title") to getTitle() - not good. So the genric getter says "if there is a custom getter, use it and return the value, else go get the data from inside the bean". In that way the interface is always get("Title") and that method is smart enough to look for and call getTitle() if it exists.

The other thing above is something else I use to remove a lot of my methods and replace them with metadata.
# Posted By Peter Bell | 4/19/07 9:29 AM
@David,

Thanks for posting on the above. There is precious little information about dynamic CFML so your post was appreciated.

I thought I would give your example a go.

For this example, assume a CFC called User is in scope. On the CFC is a method called getUserID. The User.cfc stores the UserID internally as variables.instance.userID.
Finally, the function 'getUserID' simply returns variables.instance.UserID. All Boilerplate bits so far.

When I use the technique you outlined above to call the method, it seems to decouple itself from the User component and lose all knowledge of whence it came, throwing this error:

'Element INSTANCE.USERID is undefined in VARIABLES.'

Which leaves me to believe that when calling an external CFC, the only two ways to leave the scope intact is cfinvoke or evaluate. Is there another technique I am missing?


Dan Wilson
# Posted By Dan Wilson | 4/20/07 6:53 AM
Dan,

I just did some quick testing and your conclusion seems correct.

From what I understand of Peter's examples they look like they are running inside a CFC, so even if you move the function in to a variable INSIDE a the CFC you will have no problems as it will have access to all the scopes/variables in that CFC.

Peter is doing lots of funky stuff in his method to make one call that then function (dynamically) calls other getters inside the CFC itself.

So, if a function does rely on state inside a CFC, from outside the CFC you can't assign it to a variable/structure and call it, as it won't have access to the "state" of the originating CFC.

However, if you move that function in to another CFC that has that state, it will work.

If you want to look at my testing code, it is here: http://www.harrisfamily.net.nz/devblog/enclosures/...

I haven't really used this in "real life" myself, but I would check out (Guru) Hal Helms if I started to.
See: http://www.halhelms.com/index.cfm?fuseaction=newsl...

HTH
# Posted By David Harris | 4/21/07 10:41 PM
Hi David,

Great post.. I thought it had solved my problem with having to use evaluate but unfortunately it hasn't due to the need to create a method in the CFC I am attempting to dynamically call a function from (to ensure state is maintained).

I can't do this as the CFC I am accessing is a singleton. To get this to work I would have to create a random function name each time right? That is possible but it seems a longwinded way to allow me to call a CFC method that isn't known at runtime.

I really would prefer not to use evaluate but can't see how I can avoid it in this instance.. :(

Thanks for the insight though.. I've learnt something from this - the ability to call functions by assigning them to a variable and then calling that as a function..neat.
# Posted By James Allen | 3/12/08 11:46 AM