Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Johnathan Hunt
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Johnathan Hunt ( @JHuntSecurity )

Default CFParam Expressions Are Always Executed In ColdFusion

By on
Tags:

Yesterday, my world was somewhat rocked when I discovered that default CFArgument expressions are executed only as-needed in the ColdFusion runtime. This was awesome news; and, it made me wonder if I've been wrong about other contexts that can employ default values. The one that immediately jumps to mind is the CFParam tag which can assign a default value to a variable reference if it is not already defined.

To test this, I set up a similar situation - I am employing a getDefaultValue() function in my CFParam tags; but, I am only requiring it (theoretically) for 2 out of 5 parameters:

<cfscript>


	// I return a default value for use in an optional parameter.
	numeric function getDefaultValue() {

		return( ++defaultValue );

	}


	// ------------------------------------------------------ //
	// ------------------------------------------------------ //


	// Since the defaultValue is pre-incremented above, we will be
	// able to see how many times the getDefaultValue() method is
	// actually invoked at runtime.
	defaultValue = 0;

	// Setup THREE out of FIVE optional parameters.
	url.a = "exists-already";
	url.b = "exists-already";
	url.c = "exists-already";

	// Now, param five values. Since we have the three above, only
	// two of the five below should receive the default value.
	param name = "url.a" type = "any" default = getDefaultValue();
	param name = "url.b" type = "any" default = getDefaultValue();
	param name = "url.c" type = "any" default = getDefaultValue();
	param name = "url.d" type = "any" default = getDefaultValue();
	param name = "url.e" type = "any" default = getDefaultValue();

	// At this point, "defaultValue" will report the number of
	// times the getDefaultValue() expression was executed.
	writeOutput( "Script Result: " & defaultValue );

	// Output the URL values at this point, so we can see which
	// values were defined.
	writeOutput( "<br />" );
	writeOutput( "Url: #a#, #b#, #c#, #d#, #e#" );


</cfscript>

When I run this code, I get the following page output:

Script Result: 5
Url: exists-already, exists-already, exists-already, 4, 5

Here, we see a different behavior than we saw yesterday with the CFArgument tag. In the CFParam context, the default expression is executed for every CFParam statement; however, the generated value is only applied to the last 2 CFParam tags that do not have pre-defined variable references.

This is more in alignment with my long-standing notions about default-expression evaluation. Though, I have to admit, I much prefer the way it's handled in the CFArgument tag. As a final note, I should mention that this same behavior is exhibited in a Tag-context, but I didn't bother showing it.

Want to use code from this post? Check out the license.

Reader Comments

16 Comments

Dammit! I've got a blog article half-written on this very subject. How weird is that (in the sense of "coincidence"). Will have to come up with something else now. Damn you, Nadel. ;-)

--
Adam

15,640 Comments

@Adam,

Ha ha, sorry!

If you want something to look into, I just tried running this in both Adobe / Railo using CFLive.net. They have two very different outcomes. I don't know *anything* about the Railo engine, so I am not sure what that means. I know you poke around with Railo, so maybe that will make more sense to you.

24 Comments

Yeah, this is a fun one. It makes sense and is sooo frustrating at the same time.

It would be really cool if a "deferred" attribute could be added to cfparam so that it basically did an EVAL of the default value expression if the variable needed to be set, and did NOTHING if the variable existed already.

7 Comments

The difference on Railo has to do with scopes. I think Railo is implying a local scope on the variable in the function and default initializing it to 0. When you replace defaultValue with variables.defaultValue both ACF and Railo return the same results.

15,640 Comments

@Tom,

Ah, interesting. I am not sure how I feel about that. It seems to go against what other languages [that I use] do, ex. JavaScript.

7 Comments

@Ben,

I fully agree that the Railo functionality is wrong. CFML is supposed to look for variables in existing scopes before creating new ones. It can make the code hard to read, but that's the way it's work with ACF since as far as I can remember.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel