Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with:

Named Arguments In ColdFusion Depend On The Argument Collection, Not The CFArgument Tags

Posted by Ben Nadel
Tags: ColdFusion

Last night, I was laying in bed thinking about Jenna Elfman in Can't Hardly Wait (one of the best coming-of-age movies ever), when suddenly, I started thinking about named arguments in ColdFusion. I know I've probably covered this a number of times before but, I wanted to test the behavior of named arguments when no CFArgument tags were present in a function. In essence, I wanted to double-check whether named arguments required CFArgument tags; or, if the very existence of them in the ArgumentCollection was sufficient. Part of this curiosity ties into stuff Elliott Sprehn discussed at CFUNITED 2010 - but, more to come on that later.

If you look at the way ColdFusion 9's new CFScript-based tag components (ex. Query.cfc) work, it is clear that named arguments do not need to have corresponding CFArgument tags; but, since I want to build on this behavior, I wanted to run a quick test to setup a foundation for future exploration. In the following code demo, all I have is a ColdFusion user defined function that CFDump's out its arguments scope. You will notice here that the UDF does not have any predefined CFArgument tags:

  • <cffunction
  • name="doSomething"
  • access="public"
  • returntype="any"
  • output="true"
  • hint="I simply output my arguments scope to see how named arguments work without CFArgument tags.">
  •  
  • <!--- Dump out the arguments. --->
  • <cfdump
  • var="#arguments#"
  • label="Arguments Scope."
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  •  
  •  
  • <!--- Create an argument collection with named arguments. --->
  • <cfset arguments = {
  • name = "Tricia",
  • hair = "Blonde",
  • isSassy = true
  • } />
  •  
  • <!---
  • Invoke our argument tester method, passing in our named
  • arguments as the argument collection.
  • --->
  • <cfset doSomething( argumentCollection = arguments ) />
  •  
  •  
  • <br />
  •  
  •  
  • <!---
  • Now, just as a test, let's try it one more time with a
  • completely different set of arguments (there's no real need
  • for this test, I just like to be thorough).
  • --->
  • <cfset arguments = {
  • name = "Deadlift",
  • weight = "315",
  • reps = "8"
  • } />
  •  
  • <!--- Test the invocation one more time. --->
  • <cfset doSomething( argumentCollection = arguments ) />

Once doSomething() - my user defined function - is defined, I create two arbitrary structs to use as my invoking argumentCollection. Calling doSomething() and passing in each struct gives me the following CFDump output:

 
 
 
 
 
 
Named Arguments In ColdFusion Depend On The ArgumentCollection Structure, Not On The CFArgument Tags. 
 
 
 

As you can see, the name-value pairs in our arbitrary argumentCollection structs are translated into the named arguments available within the CFFunction's arguments scope. While the existence of CFArgument tags can help map positional arguments to named arguments, there is nothing about named arguments that requires CFArgument tags.

This demonstration isn't ground-breaking in any way; but, as someone who is compulsive about defining CFArgument tags within my CFFunctions, I simply wanted to double-check this behavior before I moved onto some more complex concepts that leverage this functionality.




Reader Comments

@Michiel,

I don't mean to imply that you *shouldn't* use CFArguments tags; they are definitely great for code readability and self-documentation. I just wanted to confirm the behavior before I started to look into something a bit more deeply.

Reply to this Comment

Jenna Elfman is one of those actresses who will make me think twice about watching a movie because I find her so annoying. However, "Can't Hardly Wait" is so good I can overlook her presence (and my friend Amber is in it, so... :)

Reply to this Comment

@Wendy,

Have you seen Keeping The Faith? She is excellent in that. I don't think I've seen her in much else.

Reply to this Comment

Netflixed it (at your suggestion :) and couldn't get through it because I found her so annoying. She's done a couple of tv shows, and I couldn't watch those either. She just bugs the stuffing out of me (and not just because she's a card-carrying Scientologist). Don't think I will ever get over my anti-Elfmanism.

Reply to this Comment

@Wendy,

Fair enough - to each their own. I found her very much the opposite in Keeping The Faith; her character just seemed to be very endearing.

@Tim,

Elliott was doing some very interesting argument overloading trickery in his presentation. I just wanted to explore some of those concepts a bit more deeply, see what I might be able to do with them.

Reply to this Comment

Hmm... well, to be totally honest, I only watched the first scene with her in it and shut it off. Maybe I shouldn't be so narrow-minded (yes, I actually said that). I really love Edward Norton; he is such a quality actor!

Reply to this Comment

Since you're just looking to confirm the behavior, it should be noted that this is not limited to named arguments but also works for positional arguments (in CF8 anyway). I agree that this does greatly reduce code readability, but is good to know.

Reply to this Comment

@Jeremy,

Ah yes, good point. I think that should work pre-CF8 as well. If anyone doesn't understand what Jeremy is referring to, he means you can always reference positional arguments via the arguments scope:

arguments[ 1 ]
arguments[ 2 ]
... etc.

You can even use named-arguments to fenagel ordered arguments:

<cfinvokeargument name="1" value="foo" />
<cfinvokeargument name="2" value="bar" />

Good stuff.

Reply to this Comment

I was reading the same topic in morning...nice to see this again in evening with much better example..

Reply to this Comment

@Ben

You couldn't pass positional arguments with argumentCollection or cfinvokeargument name="1" (etc.) before 8.0.1.

That's the reason ColdSpring and many other frameworks looked at the metadata of functions to get the argument names to use cfinvoke. The only reason not to use this feature is if you're supporting CF7.

Ideally we'll get component[method](a,b,c) syntax in CF10. Railo already supports it. We really wanted it in CF9, but they didn't get around to it.

Reply to this Comment

@Elliott,

Ahh, thanks for the clarification. I was not aware that that behavior was added after the CFInvokeArgument tag. As far as the component[method](), they neeeed to add that - it would make certain things so much easier.

Reply to this Comment

@Elliott,

i use:
variables.gf_stupid_cf_parser = component[method]
and then call
variables.gf_stupid_cf_parser( a,b,c )

is there a better workaround ?

Reply to this Comment

@Nelle,

The problem with that is that once you get the method reference out of the component, it is no longer bound to the component when it is executed. As such, once you get the reference to "gf_stupid_cf_parser ", you are executing it in the context of the variables scope and will not have access to the component's private scope.

Reply to this Comment

@Ben,

indeed, the method then has no access to the "this" scope.

for methods which need it, the approach could be modified to:
component.gf_stupid_cf_parser = component[method]
component.gf_stupid_cf_parser( a,b,c )

but the question remains, is this really the best way to do it ?

Reply to this Comment

@Nelle,

Ahhh, I see what you're saying; I don't think I was following you at first. That's a really interesting idea - storing the method reference *back* into the component with a known name. That's a clever idea.

I suppose, until we can do component[method](), we can still use the CFInvoke and CFInvokeArgument tags:

<cfinvoke component"#component#" method="#method#">
<cfinvokeargument name="a" value="x" />
<cfinvokeargument name="b" value="y" />
<cfinvokeargument name="c" value="z" />
</cfinvoke>

... but clearly WAY more verbose.

Reply to this Comment

Post A Comment

?
You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.