A reader asks:
Hi there Jedi. So which is better to do? Check for a null URL value using CFPARAM or CFisDefined? CFPARAM is so much straightforward and usually seems to work just about any place I need it. I have no idea why some folks opt for CFisDefined (if I'm even getting that tag right).
First off - neither is better. Each does exactly what you want them to do. CFPARAM will create a variable if one doesn't exist (and optionally do type checking), while isDefined only checks for the existence of a variable. So again - one isn't better than the other. You simply use the one that makes sense.
Now, what you may be asking is - why would folks do the following instead of CFPARAM:
<cfif not isDefined("url.id")>
<cfset url.id = 1>
</cfif>
There are a few reasons. First off - you typically pass a hard coded value to CFPARAM, but you may have more complex logic. In other words, you may want to day, if URL.ID is not defined, and it is in the morning, do this, otherwise do that. While you could point CFPARAM to a UDF that did that, it would be more readable to use cfif and isDefined. Another example - if url.id does exist, you may want to preload a bunch of form variables with data from the database. If url.id does not exist, you may want to default those values. You may then choose to use isDefined instead.
Another possibility - while CFPARAM can do optional type checking, it can't be as precise as you may like. So I can tell CFPARAM to ensure a value is numeric, but I can't check to see if the value is an integer or greater than zero.
Anyone else have a comment on why they would use one over the other?
Archived Comments
my reasoning is that isDefined is the closest coldfusion has to NULL, it always seems dirty to set a variable to "" when it is actually undefined. Ahh it's all in the details
well here is my logic.
I use CFPARAM whenever I have variables that are required and I'm not setting them for within my templage. A most common example is a form post.
I use isdefined when I'm checking for the existance of a value within a variable. Mostly this has to do with Arrays and Structures. An example of this is
<!---///
Here is a combo exmaple.
I use cfparam to make sure that I got the structure from the form post.
I then use isdefined to make sure that the structure contains the key I want.
Yes and I know that you would never have a form post a structure. I just did
this to show both methods.
///--->
<cfparam name="form.PostStructure" default="" type="struct">
<cfif isdefined("form.PostStructure.firstname")>
<cfoutput>#firstname#</cfoutput>
</cfif>
isDefined works well on form submissions when checking which button was pressed such as having a submit button named "submit".
<cfif isDefined("form.submit")>
The cfparam default attribute can be dynamic, such as assigning url scope to form scope.
<cfparam name="url.fuseAction" default="mainMenu">
<cfparam name="form.fuseAction" default="#url.fuseAction#">
The cfparam name attribute can even be dynamic, such as iterating over a list to generate the cfparams.
<cfset lstFormFields = "name,address,city,state,zip,telephone,fax,mobile,email">
<cfloop list="#lstFormFields#" index="fname">
<cfparam name="form.#fname#" default="">
</cfloop>
I really like being able to use a cfparam with a regex validator. You could actually solve one of the things you said with it. For example a regex could look for the inclusion of a . to see if it's an integer. You could use regex to see if total numbers in a string are gt than 1 and if so that the first number has to be 1-9 and that would tell you for example if the number is GTE than 10.
That being said, I still use isDefined alot more than cfparam since I do mainly DAO's with a validate method now and that means im doing the methods myself.
I would use structKeyExists as all CF variables are in a structure (form, url, varaibles, etc).
<cfif not structKeyExists(url,"id")>
<cfset url.id= -1>
</cfif>
I believe this will be slightly quicker than using isDefined.
I’ve personally also used isDefined() over CFPARAM simply because I was already within a CFSCRIPT block and didn’t want to break out of it simply to default my variables.
Ray, can you comment on the use of isValid() over isDeifned()? To me it seems like a better way to handle this over the traditional if/isDefined combination because it would allow typing checking (and may be a bit cleaner code too). Is there anything that should be considered when using isValid() in this way (performance or other caveats.)
isDefined() is bad m'kay.
Where ever possible you should use structKeyExists() rather than isDefined() to test for the existence of scope variables.
There are numerous reasons for this, but the primary one is that isDefined() looks in all scopes to see if the variable exists. That means that if you do this:
<cfif isDefined("url.myvar")>
<!--- do something --->
<cfelse>
<!--- do something else --->
</cfif>
If the variable doesn't exist in the URL scope, the CF engine goes off and looks in all the implicit scopes to see if there's a variable called URL in them. If there is, it checks to see if it's a struct containing a myvar key.
That has some minor performance implications, and some pretty serious bug stomping ones. If you accidentally create a variable called url.myvar in one of the implicit lookup scopes you can have a hell of a time trying to figure out why this URL variable mysteriously appears and disappears, or why some weird default value seems to be getting inserted.
As for whether to use cfparam or structKeyExists() I think that's been pretty well covered by everyone else.
Spike - I'm not so sure I agree with you. I mean - what you say is technically right, but I don't know if I agree with the seriousness of it. While I'm sure people do it - I have yet to see someone make a variable called url.something in the form scope. Again - it could happen.... I'm not denying that. As for the performance issue - again - I don't deny it will be slower, but I'd argue that if it makes your code more readable to use isDefined (which is probably a personal decision), then you shouldn't be afraid to use it. My 2 cents.
I would agree with you if it was purely a performance thing, but it's not. You can all too easily introduce a very subtle bug if you don't use structKeyExists(). For starters, you don't have to put the scope prefix with isDefined(). With structKeyExists() you do.
Take this example:
<!--- Whoops! forgot to put the URL prefix here --->
<cfif NOT isDefined("username")>
<cfelse>
</cfif>
That code might work perfectly until you have a cookie called username, a form variable called username, the same in any of the other implicit scopes.
That's 2 votes against isDefined(). It still works correctly if you either deliberately or accidentally leave off the scope prefix, and even if you do, it can still fail because of the implicit scope lookup.
I'm not suggesting for a minute that people go around creating session.url or session.form as a matter of course, but I've seen stranger things happen accidentally as a side-effect of some other code. That's the sort of thing that's incredibly hard to track down and debug.
Ah - even if isDefined was faster than cfparam, I'd still warn folks away from NOT using a fully scoped variable. That's just plain bad - but I don't consider it a 'vote' against isDefined. It is a vote against not scoping your variables.
The fact that isDefined() allows this to escape un-noticed is why I said it's a vote against.
It's much easier to spot that someone's using isDefined() instead of structKeyExists() than to spot that they've forgotten to scope the variable inside isDefined().
It's a question of the machine catching the bug rather than you having to be a "perfect" human being. We all know we can't be that, so I prefer to take advantage of those little bits of assistance I can get by using structKeyExists() instead of isDefined().
Perhaps. I'm still not entirely convinced - but I see your point.
I'm with spike on that one, structkeyexists makes much more sense in most cases and forces you to think of the scope. IsDefined almost feels like a depreciated function now.
With isDefined("url.foo") CFMX will keep searching out through scopes to see if it can find a match:
cfset variables.url.foo = 42
isDefined("url.foo") is TRUE
structKeyExists(url,"foo") is FALSE
I never use isDefined() unless I have one of those extremely rare cases where I don't know the scope / format of a variable name, e.g., isDefined(someVariable) as opposed to isDefined("someVariableName").
Does anyone know if isValid() also search through the scopes the same way isDefined() does? According to Pete Freitag the IsValid() function performs data validation just like the CFPARAM tag:
http://www.petefreitag.com/...
Does that include how scope searching is done?
If isValid() does not have the same problems as isDefined(), I personally would strongly favor that over structKeyExists() since it seem to more explicitly state what its intended purpose is (to initialize/default/define the variable).
Robert, no, isValid() just tests *values* not variable names.
Got it, sorry I misunderstood Pete.
Thanks for the clarification.
I apologize, did mean to confuse things.
In the context of <cfparam> vs. isDefined() neither is better, the 'better' choice is the one that makes the most sense for what you are trying to accomplish. For instances, if you require certian variables to exist in your template before you use them, then you might be better off using <cfparam>:
<!--- Blow up if the variable is missing --->
<cfparam name="request.iamrequired" type="array">
If on the other hand you weren't concerned if a variable exists but would take some action if it was, then you might be better off using isDefined() or structKeyExists().
<!--- Do I take some action? --->
<cfif isDefined("request.somevariable")>
<!--- Do something here --->
<cfelse>
......
There are many different scenarios that would make one a better choice than the other, again it all depends on what you want to do.
Ah! Well as the submitter of the original question, I'd like to thank the Jedi for clearing this up. And he is correct, my question WAS more specifically, why do some people use an isDefined/If combo over CFPARAM. I can see now that isDefined does offer a lot more in terms of ancillirary action if you desire that upon discovery of non-present (or present) variable. I'm still learning, so it's going to take me awhile to understand the relevance of the other points being discussed in this comment area. I have no idea why I'd ever use a "strucKeyExists", but that's for another (more advanced) day! LOL
I'm with Ray on this one, and then some.
isDefined() vs. structKeyExists() is an entirely separate issue to explicit variable reference scoping.
Arguing otherwise, to me, sounded like saying "You should drive a minivan instead of a coupe because a minivan won't even let you break 100 miles per hour, so you won't have to worry about how 'perfectly' you're driving, your maximum damage is that derived from the force achieved with a speed no greater than 100 mph. It's a type of preventative maintenance, although, you'll never be able to go as quickly or turn as sharply and efficiently as you could in a coupe."
And yes, I enjoy exaggeration.
Whether you choose not to use explicit scoping in every variable reference in all of your code (with rogue, sporadic, legitimately strategic exceptions discussed by Ben in the certified developers' study guide) is your own conscious defect, not the inevitable result of a faulty programming style.
All costs and benefits considered, isDefined is MUCH MORE READABLE and fluid than structKeyExists. It's a more concise, obvious function name, with a single parameter which instantly, logically describes scope in a single location. structKeyExists has one parameter with and one without quotation marks (though I use single apostrophes), is less intuitively named (isStructKey would better follow suit to isDefined and other preferred naming patterns), and is slower to type, revise, and implement with dynamic values.
These minutia cumulatively entail a few monumental differentials.
1. structKeyExists, I've heard, though I'm not fully convinced because it's hard for me to accept that keyword-scoped variable names aren't exempt from the order-of-evaluation process, that structKeyExists will provide minimal, trivial performance gains. This, to me, is the singular legitimate benefit. But, to be honest, if you're so concerned about performance that it would prevent you from using an evaluative function like isDefined, take out a loan and buy a slightly more powerful server. I promise you'll thank me for it later.
2. isDefined can save efficient developers exponential amounts of 'human time.' The quickness, fluidity, and comfort with which you architect new code, dive back into old code, and self-document your logic with clear, easy-to-comprehend programmatic organization. Other people reading your code will thank you. You will thank your prior self once time machines are affordable. Your kids will applaud you while drifting through your life's work's sourcecode. You will save yourself and your employer, if separate, money because you will be programming MORE QUICKLY than the miniscule performance gains you purposely sacrifice by using isDefined over structKeyExists.
2 > 1 evaluates to true by about 800%.
Use isDefined. Explicitly scope 99.9995% of the time. Enjoy revisiting code like never before.
The end.
Yikes. I just read that over. My English hasn't been that bad since kindergarten. And I just realized that the prior post to mine was in 2005. Embarrassing.
I have to respectfully disagree with those who say "neither is better". I've worked with CF for several years, and I consider isdefined one of the more harmful features of the language, second only to cfinclude. These two features make managing and scaling CF applications nearly impossible, since they almost require the user to write nonsensical spaghetti code. The reader had the correct intuition. Encapsulating and declaring a template's variables at the top of the page with cfparams is infinitely cleaner, easier to document, and more maintainable than ambiguously hiding them throughout the page within murky isdefined expressions. IsDefined should give nightmares to anyone who's taken a functional or object-oriented programming class.
Wow. Thats a pretty bold statement. I have to say I do not agree with you at all. CFINCLUDE is perfectly fine tool. Like any other feature it can be misused. I do not use cfinclude for reusable functions and the like. But for things like including a common header for example it makes perfect sense.
Also - there is nothing to stop you from using cfparam in the middle of the page, or from using isdefined on top of the page.
Raymond,
If all you're using cfinclude for is to prepend a header or append a footer, then I agree, that that's an (if not *the*) appropriate usage for cfinclude. Unfortunately, most bad coders I've met rarely stop there. I've seen 6-levels of nested cfincludes, which there's really no excuse for. Not only is it impossibly obfuscated, but it's hard to trace errors since CF's error handling mechanism doesn't follow nested cfincludes very well. Granted, no language can stop bad programmers from writing bad code, but cfinclude should really be redesigned to throw an exception if it's used more than one level deep.
And I'm much less concerned with cfparams being used elsewhere in a template, because at least they're deterministic. If you see a cfparam, you know something is *definitely* defined. Obviously, with isDefined() that's not the case. If some poor coder has wrapped a huge chunk of code conditioned with an isDefined(), then there's a good chance you'll waste a lot of time reverse engineering the code to try and find where (if at all) that variable's defined.