isDefined() tries very hard to find any possible definition of the requested variable. It searches through the scopes as if the variable name is not scope-qualified - even when it contains a dot (.) which seems to date back to pre-MX ColdFusion which allowed dots in variable names. For example, if you say:
In all cases, structKeyExists() lets you test for variable existence much more precisely:
structKeyExists(variables,"variables") is YES
structKeyExists(variables.variables,"foo") is YES
structKeyExists(variables,"test") and structKeyExists(variables.test,"foo")
You need both.
Short answer: structKeyExists is SLOWER and has no advantage other than forcing coder to use scoping, which s/he should do anyway...
Long Answer:
whereas for the examples below url.pageid is a real url variable
STRUCTKEYEXISTS: structKeyExists is pretty much the same speed no matter what you throw at it, keys can be real or not (url, 'pageid' and url, 'pageadfasdf' are about the same, no big diff one way or the other) and if you throw a scope at it that does not exist, it throws, so it forces you to be careful about scoping.
ISDEFINED: isDefined is super fast when the scope exists and you pass in a scope (url.pageid), however, it is extremely extremely mega super slow when you pass in a non-existant scope (urlss.pageid). it is also super super mega slow if you pass in a non-scoped non-existant variable (pagelksjdljsdf) it is quite fast, on average 10 to 20% faster than structKeyExists, when you pass in a SCOPED variable, existant or not (url.pageid or url.aoiausldkjf)
So what does that mean in real life? Well, as long as you are asking for a SCOPED variable that is extant, and you don't mispell the scope (url for instance), isDefined will be faster on average.... If you are looking for a NON-SCOPED variable, you have no choice but to live with isDefined.... hum....which can be very very slow when the variable does not exist. If you want to make sure you scope all your vars, use structKeyExists and live with a small speed hit, but be assured it is scoped to a real scope (or throw an error). So for me, in real life use, that means isDefined is probably the better choice as it is overall going to be faster as long as i can spell my scope correctly. It also is the only choice to use when looking for multiple scope variables such as FORM.ID vs URL.ID and your page/function can take either and want to simply ask isDefined('ID') but if you want to prioritize one over the other (which you probably should) then you can again use either define/struct where you have a little bit of script that checks each (form.id and then url.id) and assigns a variables.myID which is then passed in to page/function to use.... again, this would indicate isDefined would be preferred as it would be faster for that call too, as long as it is scoped and the scope exists. So I can't find any reason to use structKeyExists other than it might seem like better code because it forces scoping.... How sad... it seemed like it should be faster as it specifies the scope....
here is sample code for you to run and see for yourself.... i'd love to know if you find anything different than what I did by platform or other (I am using CFMX702 on a WINDOWS platform). Is linux version any faster? Anyone know what actually happens at the compiled java level?)
<CFSCRIPT> ITERATIONS = 100000; writeoutput('ITERATIONS : ' & ITERATIONS & '<BR>' ); i=0; j=0; k=0; ttt1 =0; ttt2 =0; t1c =0; t2c=0;
for(k; k lte ITERATIONS; k=k+1){
T1 = getTickCount(); for(i; i lte ITERATIONS; i=i+1){ if(isdefined('url.asdfpageid')){ //do nothing } } T2 = getTickCount(); TT1 = T2-T1; ttt1=ttt1+TT1;
T3 = getTickCount(); for(j; j lte ITERATIONS;j=j+1){ if(structKeyExists(url, 'pageeid')){ //do nothing } } T4 = getTickCount(); TT2 = T4-T3; ttt2=ttt2+TT2; if(TT1 gt 0){t1c = t1c+1;} if(TT1 gt 0){t2c = t2c+1;}
if(TT1 gt 0 or TT2 gt 0){writeoutput('Iteration K: ' & k & ' isDefined: ' & TT1 & 'ms'); writeoutput(' structKeyExists: ' & TT2 & 'ms<br>');}
}
writeoutput('<BR>Times isDefined used time: ' & t1c); writeoutput('<BR>Times structKeyExists used time: ' & t2c);
writeoutput('<BR>FINAL isDefined: ' & TTT1 & 'ms'); writeoutput('<BR>FINAL structKeyExists: ' & TTT2 & 'ms');
</CFSCRIPT> <br>
<!--- The cfchart ---> <cfchart format="flash" xaxistitle="function" yaxistitle="Loading Time"> <cfchartseries type="bar" serieslabel="isDefined"> <cfchartdata item="isDefined" value="#variables.TTT1#"> </cfchartseries> <cfchartseries type="bar" serieslabel="structKeyExists"> <cfchartdata item="structKeyExists" value="#variables.TTT2#"> </cfchartseries> </cfchart>
2 sets of runs, 15 run throughs, not a single instance of structKeyExists as faster...
i'll post the code and results in two following posts.
<CFSCRIPT> ITERATIONS = 1000000; writeoutput('ITERATIONS : ' & ITERATIONS & '<BR>' ); i=0; j=0; k=0; ttt1 =0; ttt2 =0; t1c =0; t2c=0;
for(k; k lte ITERATIONS; k=k+1){
T1 = getTickCount(); for(i; i lte ITERATIONS; i=i+1){ if(isdefined('url.pageid')){ //do nothing } } T2 = getTickCount(); TT1 = T2-T1; ttt1=ttt1+TT1;
T3 = getTickCount(); for(j; j lte ITERATIONS;j=j+1){ if(structKeyExists(url, 'pageid')){ //do nothing } } T4 = getTickCount(); TT2 = T4-T3; ttt2=ttt2+TT2; if(TT1 gt 0){t1c = t1c+1;} if(TT2 gt 0){t2c = t2c+1;}
if(TT1 gt 0 or TT2 gt 0){writeoutput('Iteration K: ' & k & ' isDefined: ' & TT1 & 'ms'); writeoutput(' structKeyExists: ' & TT2 & 'ms<br>');}
}
writeoutput('<BR>Times isDefined used time: ' & t1c); writeoutput('<BR>Times structKeyExists used time: ' & t2c);
writeoutput('<BR>FINAL isDefined: ' & TTT1 & 'ms'); writeoutput('<BR>FINAL structKeyExists: ' & TTT2 & 'ms');
if(TTT1 GT TTT2){ writeoutput('<BR>structKeyExists is faster by: ' & TTT1-TTT2 & 'ms which is ' & NUMBERFORMAT((TTT1-TTT2)/TTT1*100, '9.9') & '% faster'); }else{ writeoutput('<BR>isDefined is faster by: ' & TTT2-TTT1 & 'ms which is ' & NUMBERFORMAT((TTT2-TTT1)/TTT2*100, '9.9') & '% faster' ); }
</CFSCRIPT>
<br>
<!--- The cfchart ---> <cfchart format="flash" xaxistitle="function" yaxistitle="Loading Time"> <cfchartseries type="bar" serieslabel="isDefined"> <cfchartdata item="isDefined" value="#variables.TTT1#"> </cfchartseries> <cfchartseries type="bar" serieslabel="structKeyExists"> <cfchartdata item="structKeyExists" value="#variables.TTT2#"> </cfchartseries> </cfchart>
Times isDefined used time: 107 Times structKeyExists used time: 118 FINAL isDefined: 4925ms FINAL structKeyExists: 5641ms isDefined is faster by: 716ms which is 12.7% faster
Times isDefined used time: 123 Times structKeyExists used time: 136 FINAL isDefined: 5255ms FINAL structKeyExists: 5626ms isDefined is faster by: 371ms which is 6.6% faster
Times isDefined used time: 104 Times structKeyExists used time: 138 FINAL isDefined: 5792ms FINAL structKeyExists: 6002ms isDefined is faster by: 210ms which is 3.5% faster
Times isDefined used time: 148 Times structKeyExists used time: 150 FINAL isDefined: 6221ms FINAL structKeyExists: 6375ms isDefined is faster by: 154ms which is 2.4% faster
Times isDefined used time: 349 Times structKeyExists used time: 318 FINAL isDefined: 21747ms FINAL structKeyExists: 23098ms isDefined is faster by: 1351ms which is 5.8% faster
Times isDefined used time: 271 Times structKeyExists used time: 325 FINAL isDefined: 14802ms FINAL structKeyExists: 31557ms isDefined is faster by: 16755ms which is 53.1% faster
Times isDefined used time: 300 Times structKeyExists used time: 293 FINAL isDefined: 25496ms FINAL structKeyExists: 35296ms isDefined is faster by: 9800ms which is 27.8% faster
Times isDefined used time: 333 Times structKeyExists used time: 271 FINAL isDefined: 22676ms FINAL structKeyExists: 26463ms isDefined is faster by: 3787ms which is 14.3% faster
Times isDefined used time: 245 Times structKeyExists used time: 268 FINAL isDefined: 11288ms FINAL structKeyExists: 15934ms isDefined is faster by: 4646ms which is 29.2% faster
Times isDefined used time: 220 Times structKeyExists used time: 267 FINAL isDefined: 11470ms FINAL structKeyExists: 16012ms isDefined is faster by: 4542ms which is 28.4% faster
Times isDefined used time: 266 Times structKeyExists used time: 281 FINAL isDefined: 10572ms FINAL structKeyExists: 13946ms isDefined is faster by: 3374ms which is 24.2% faster
Times isDefined used time: 278 Times structKeyExists used time: 275 FINAL isDefined: 10125ms FINAL structKeyExists: 13329ms isDefined is faster by: 3204ms which is 24.0% faster
Times isDefined used time: 242 Times structKeyExists used time: 253 FINAL isDefined: 10067ms FINAL structKeyExists: 14494ms isDefined is faster by: 4427ms which is 30.5% faster
Times isDefined used time: 192 Times structKeyExists used time: 221 FINAL isDefined: 7526ms FINAL structKeyExists: 12226ms isDefined is faster by: 4700ms which is 38.4% faster
Hum...on my random pulls, i usually see about 1 in 10 where structKeyExists is faster, but this particular series (ran in 5 windows 3 times each concurrently, thus under some load), I didn't get any...
15 pulls where scope and key exist.
Times isDefined used time: 312 Times structKeyExists used time: 317 FINAL isDefined: 7706ms FINAL structKeyExists: 8730ms isDefined is faster by: 1024ms which is 11.7% faster
Times isDefined used time: 311 Times structKeyExists used time: 338 FINAL isDefined: 8596ms FINAL structKeyExists: 17218ms isDefined is faster by: 8622ms which is 50.1% faster
Times isDefined used time: 326 Times structKeyExists used time: 314 FINAL isDefined: 12959ms FINAL structKeyExists: 16560ms isDefined is faster by: 3601ms which is 21.7% faster
Times isDefined used time: 301 Times structKeyExists used time: 275 FINAL isDefined: 12339ms FINAL structKeyExists: 16680ms isDefined is faster by: 4341ms which is 26.0% faster
Times isDefined used time: 298 Times structKeyExists used time: 322 FINAL isDefined: 12346ms FINAL structKeyExists: 17918ms isDefined is faster by: 5572ms which is 31.1% faster
Times isDefined used time: 350 Times structKeyExists used time: 347 FINAL isDefined: 12619ms FINAL structKeyExists: 17863ms isDefined is faster by: 5244ms which is 29.4% faster
Times isDefined used time: 358 Times structKeyExists used time: 331 FINAL isDefined: 12248ms FINAL structKeyExists: 18148ms isDefined is faster by: 5900ms which is 32.5% faster
Times isDefined used time: 374 Times structKeyExists used time: 363 FINAL isDefined: 9712ms FINAL structKeyExists: 12739ms isDefined is faster by: 3027ms which is 23.8% faster
Times isDefined used time: 320 Times structKeyExists used time: 355 FINAL isDefined: 15134ms FINAL structKeyExists: 19300ms isDefined is faster by: 4166ms which is 21.6% faster
Times isDefined used time: 314 Times structKeyExists used time: 324 FINAL isDefined: 14377ms FINAL structKeyExists: 19059ms isDefined is faster by: 4682ms which is 24.6% faster
Times isDefined used time: 291 Times structKeyExists used time: 349 FINAL isDefined: 13776ms FINAL structKeyExists: 21890ms isDefined is faster by: 8114ms which is 37.1% faster
Times isDefined used time: 360 Times structKeyExists used time: 351 FINAL isDefined: 13814ms FINAL structKeyExists: 23769ms isDefined is faster by: 9955ms which is 41.9% faster
Times isDefined used time: 244 Times structKeyExists used time: 247 FINAL isDefined: 9884ms FINAL structKeyExists: 14090ms isDefined is faster by: 4206ms which is 29.9% faster
Times isDefined used time: 293 Times structKeyExists used time: 266 FINAL isDefined: 9830ms FINAL structKeyExists: 13967ms isDefined is faster by: 4137ms which is 29.6% faster
Times isDefined used time: 312 Times structKeyExists used time: 315 FINAL isDefined: 8854ms FINAL structKeyExists: 11584ms isDefined is faster by: 2730ms which is 23.6% faster
hum... well... not sure what to say. even worse than what i get on my development machine.
Times isDefined used time: 786 Times structKeyExists used time: 746 FINAL isDefined: 2278ms FINAL structKeyExists: 1790ms structKeyExists is faster by: 488ms which is 21.4% faster
As I said in several places, I've had specific problems with isDefined() so I avoid it - except in the one case where I've needed it: for testing against null in the result of a method call:
var res = obj.someMethod(args);
if ( isDefined('res') ) ...
Currently there's no other way to test for null results (in ColdFusion, at least).
<cffunction name="onRequest" returntype="boolean"> <cfargument name="targetPage" type="string" required="true" /> <cfif isUserLoggedIn()> <cfif not structKeyExists(session,"user")> <!--- do something ---> <cfinclude template="test.cfm"> <cfelse> <cfinclude template="#arguments.targetPage#"> </cfif> </cfif> <cfreturn true /> </cffunction>
behave so differently from this:
<cffunction name="onRequest" returntype="boolean"> <cfargument name="targetPage" type="string" required="true" /> <cfif isUserLoggedIn()> <cfif not isDefined(session.user)> <!--- do something ---> <cfinclude template="test.cfm"> <cfelse> <cfinclude template="#arguments.targetPage#"> </cfif> </cfif> <cfreturn true /> </cffunction>
Second, you don't say how those two pieces of code behave "so differently" so it is hard to tell what you're asking...


