Luis asks:
Do you know of any way to dynamically create the condition for an if statement? I think the best way to explain this is with an example. I'm looking do to something along the lines of the following
<cfset firstElement = "hello" />
<cfset operator = "eq" />
<cfset secondElement = firstElement />
<cfif firstElement operator secondElement></cfif>I've tried various methods and variations using cfscript, iif(), and combinations of evaluate() and de(). Additionally I've searched the usual suspects for answers. (coldfusion, cf docs, cfwack, cf advanced, etc...) I realize there are longhand ways around this such as using a cfswitch to evaluate the value of operator, but I'm hoping to be able to simply support all of CF's native operators without having to essentially write the same code for each operator choice.
Most likely you just had a typo when you tried evaluate(), and frankly, evaluate can be a bit confusing at times. This code sample worked for me:
<cfset first = "ray">
<cfset second = "ray">
<cfset op = "eq">
<cfoutput>#evaluate("first #op# second")#</cfoutput>
Switching second to "paris hilton" correctly returned a false value. Note though that in general, when I see evaluate I get a bit uneasy. Evaluate is not as slow as it used to be when you use ColdFusion 8. But it always strikes me as kind of a dirty function. Like - should I really be using this? I'm not telling folks to not use it (like I used to). I will say that most of the time when I do see it - it isn't necessary.
One of the classic examples was - I have a variable that points to another variable. How do I get the value? They would then do this:
<cfset variable = "name">
<cfset value = evaluate(variable)>
But with scopes, this is a lot simpler, and easier to read I think:
<cfset value = variables[variable]>
Archived Comments
Ray - I remember a few years ago whenever evaluate was mentioned on one of the email lists that it was always you whow would pipe up first and tell people not to use it. Now you are giving examples.... tsk tsk (ha).
People change. ;) I still won't use it myself.
Silliest use of ColdFusion EVAR:
<cffunction name="op" returntype="boolean">
<cfargument name="opName" type="any" required="true">
<cfargument name="arg1" type="any" required="true">
<cfargument name="arg2" type="any" required="true">
<cfswitch expression="#arguments.opName#">
<cfcase value="and"><cfreturn arguments.arg1 and arguments.arg2></cfcase>
<cfcase value="or"><cfreturn arguments.arg1 or arguments.arg2></cfcase>
<cfcase value="not"><cfreturn not arguments.arg1></cfcase>
<cfcase value="eq"><cfreturn arguments.arg1 eq arguments.arg2></cfcase>
<cfcase value="neq"><cfreturn arguments.arg1 neq arguments.arg2></cfcase>
<cfcase value="gt"><cfreturn arguments.arg1 gt arguments.arg2></cfcase>
<cfcase value="lt"><cfreturn arguments.arg1 lt arguments.arg2></cfcase>
<cfcase value="contains"><cfreturn arguments.arg1 contains arguments.arg2></cfcase>
</cfswitch>
<cfreturn false>
</cffunction>
<cfoutput>#
op('or',
op('eq','foo','bar'),
op('contains','foobar','foo')
)
#</cfoutput>
I initially thought you might be able to use a dynamic reference to an underlying Java method (.equals or .compareTo), but CF complains about trying to use a string as a struct. You could probably finagle it, if you tried hard enough.
Ray, are there real, hard numbers anywhere that talk about the performance of evaluate on ColdFusion 8? I'm trying to make sure I make every worthwhile optimization for the new jCFC plugin and using evaluate really simplifies the readability as well as reduces the code necessary to do what I want to compared to some of the alternatives.
Also, is there a good place to go to get centralized info on ColdFusion performance and tuning outside of the Wack 3 and the release notes I found from Adobe from 2004 and a few random resources?
Ex: This page is 2007
http://blog.brianflove.com/...
And advocates avoiding evaluate and iif like the plague. But with normal ?: syntax absent in 8 I love iif and need to know the truth. Thanks!
I'm not aware of any 'hard' numbers. I do remember hearing that evaluate was a heck of a lot faster in CF8.
I think to me it is more a matter of appropriateness. Many times I've seen people use evaluate() when they don't need to. So given the example of a dynamic form field, they may do:
<cfset key = "name">
<cfoutput>#evaluate("form.#key#")#</cfoutput>
Whereas this is just as valid, and in my mind, more appropriate:
<cfset key = "name">
<cfoutput>#form[key]#</cfoutput>
I realized I just kind of duplicated what I said above. I'm old.
Hahah. No worries grampa.
The ColdFusion 8 performance brief says that evaluate in 8 is 2.9x faster than 7.0.2
But I still don't know how fast that is. Oh well.
I agree with you on usage. I love array access notation almost more than life itself.
There are some super dynamic situations where evalute (my opinion) is the best and most readable option, which is why I'm looking into this.
Thanks!
Curious to get some feedback on any alternatives for this one: using evaluate a dynamic variable when you don't know the scope? I know the scope[variablename] formate, but what if it could be session or application?
You can use structGet(). It lets you get a pointer to any scope.
Ok so what about situations where you legitimately need something like evaluate, for example:
<cfset myvar = 5 />
<cfset equation = "(myvar*2.45)/5" />
<cfset result = Evaluate(equation) />
I am doing something like this and right now I'm not happy with the performance I'm seeing from Evaluate can you think of any other way I can do this that might be faster, keeping in mind that this is super simplified and that the solution would need to support the equations being pulled from a database?
And no I can not put the computation in the database it needs to take place on the front end per environment restrictions.
Just write a simple parser that grabs the equation from the database and parses through and executes it inline, letting you get the full performance of natural CF execution and avoid evaluate altogether.
Just iterate through the string and pop all parenthesis into an array of arrays, with each index in the array being a token, and an array for each sub parenthesis. Then iterate through them all applying the rules of evaluation.
Your example after being parsed would give you this:
[ [ "myvar", "*", 2.45 ], "/", 5 ]
You'll have to make multiple passes through each array to make sure you follow the rules of mathematical expression evaluation ( like processing all * and /s before + and - ), but it won't be much code and you can just swap in calculated values for the array indexes as you iterate.
If you end up coding this out, you should CFLib it fo sho.
I may have to give that a try, though to be honest I feel like that approach may be pretty slow as well. Honestly I probably just have to change the way I'm doing this because in it's current form I think it's doomed to be sloooow.
Hi,
I have a string for example:
<cfset mystr = "
<cfquery name='qtest' datasource='ds'>
select name, lang from contacts
</cfquery>
<cfloop query='qtest'>
<cfif qtest.lang eq 1>
<p>#qtest.name#</p>
</cfif>
</cfloop>
">
I want to use this string next, for example:
<html>
<h1>Contact list</hi>
#evaluate(de(mystr))#
</html>
How i can do this?
You can't. You would need to save it to the file system and cfinclude it (or use the VFS in CF9).
Is there a way to call methods stored in a structure?
For example,
request.lang() returns a string
request["lang()"] returns an error
Just evaluate it.
<cfset meth = "lang">
<cfoutput>#evaluate("request.#meth#()")#</cfoutput>
Hi Guys,
I have a table with values under a column named: str_condition
values in this column can be : variables.bit_male / application.bit_male / isdefined('session.int_user_id')
The value can be complex as it can be.
I need to use the value of the values in the column.
Currently, what I am doing is
<cfif evaluate(query.str_condition) eq true>
.....code....
</cfif>
Now, I need to omit the evaluate and find another alternative. Can you guys help ?
Not sure you can skip the evaluate. In theory you could save to a file and cfinclude it.