My Secret Life as a Spaghetti Coder
home | about | contact | privacy statement
(and functions with arguments can take more than the defined amount)

This may be well known, but I haven't seen a lot (or anything) on it. Of course, as always, I may just be missing something.

In any case, the other day as I was looking over some old code, I (re)discovered this marvelous fact. Now, you may be wondering why on Earth I'd want to use arguments in a function where none were defined. But, I have at least one case where I think it's valuable: suppose you are following the Active Record Pattern, or really writing any ORM. Basically, you want to abstract the query process. Now, that's certainly a noble goal. But, what happens when you want to provide a filter? For instance, you might have a function find_by_id(), a which finds a record based on the id you pass in. That's easy enough. You might even provide methods to find_by_other_columns_even_in_combinations().

But surely you can't provide every combination! That's where you'd want to provide a filter argument. Here it comes again: another but! You don't want to simply provide filter="where column1=#form.column1#" - you want to parameterize the query for the developer. Now, one way to do that would be to parse the filter argument and reconstruct it using your cfqueryparams in all the right places. But, an easier way would be to something like this:

find_records("where age=? and (name=? or name=?)", 9, "blockhead", "charlie brown")



Note: I would probably move the "where" into the abstraction, and just let the programmer provide the clause, but for illustration purposes, I left it in there.

For illustration purposes, my function only does this:

<cfcomponent>
   <cffunction name="find_records" output="true">
      <cfargument name="filter">
      <cfloop collection="#arguments#" item="key">
         #key# = #arguments[key]#<br/>
      </cfloop>
   </cffunction>
</cfcomponent>

But it would be easy enough to modify it to do something useful. Right now, if you run it, you see all the arguments are available in the arguments structure. The first one comes under the key "filter", and the rest come under numeric keys, in the order they were passed (of course, looping over it won't show you that order, but the number of the key represents the position in which it was passed. Now, you can parameterize the arguments, first checking more restrictive and moving to less restrictive parameters (for instance, you'd want to check isDate(), isNumeric(), and fall back on string).

You could name the arguments too, but I haven't found that useful for this example, since they will have their names as keys in the arguments structure, and I know of no good way to figure out the order in which they were passed.

Finally, I haven't yet implemented this in cfrails, so I don't know how feasible basing parameterization on the CF type is, but I'll try to remember to post it when I do implement it. In any case, I'd be willing to bet there are other uses for this - it's just that this is the most important one on my mind recently.

Update: It did occur to me as I was writing this post that you could accomplish the same thing by using an array as a defined argument, with the added benefit of keeping your interface well defined. In all honesty, I would prefer to do it that way if you could define an array inline like: [9, "blockhead", "charlie brown"]. But the way you define arrays in Coldfusion really makes for too much code in what I'd like to accomplish with this, so in this case I'd provide a hint in the function to let a developer know it expects you to pass those arguments. This way, I get cleaner syntax and a decent solution to the interface problem.

Hey! Why don't you make your life easier and subscribe to the full post or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!


Comments
Leave a comment

Nice post. The one "argumentless" function I like to throw in a lot when developing is:

<cffunction name="Debug">
<cfdump var="#ARGUMENTS#" />
<cfabort />
</cffunction>

I have never tried mixing named and unnamed arguments, but from you have shown, it works. Sweeeeet!

Posted by Ben Nadel on Jan 15, 2007 at 01:53 PM UTC - 5 hrs

Ooops, that didnt come through:

[cffunction name="Debug"]
[cfdump var="#ARGUMENTS#" /]
[cfabort /]
[/cffunction]

Posted by Ben Nadel on Jan 15, 2007 at 01:54 PM UTC - 5 hrs

Quite alright. =) I'll need to fix that... hadn't really thought about code being nixed. I'm sure this thing might be buggy... so forgive me if you find any (and let me know!).

Also, I didn't mean to imply you could mix named and unnamed arguments... well, at least not calling it that. You can use defined arguments and undefined arguments together, but of course if you name them when calling the function, all of them must be named, or else CF throws the "you can't mix named and unnamed arguments" exception.

Posted by Sam on Jan 15, 2007 at 02:07 PM UTC - 5 hrs

Sam, sorry about misunderstanding part of the post. I am reading at about a mile a minute (have crazy deadlines today).

Posted by Ben Nadel on Jan 15, 2007 at 02:29 PM UTC - 5 hrs

Two of the more used UDFs I use in CF loop over the arguments scope. I have an arrayCreate() and structCreate() UDF that I use to emulate the [] and {} shortcut syntax in Javascript.

I find it much more convient to do:

arrayCreate("one", "two", "three");

This allows me to pass an on-the-fly array to a function as well.

The most common use of this functions is like:

arrayCreate(
structCreate(id:1, label:"one"),
structCreate(id:2, label:"two"),
structCreate(id:3, label:"three")
);

This would leave me with a 3 row array, each a struct w/an "id" and "label" key.

Posted by Dan G. Switzer, II on Jan 15, 2007 at 03:54 PM UTC - 5 hrs

Dan, I love it! I can't tell you how useful those would be.

Posted by Ben Nadel on Jan 15, 2007 at 04:43 PM UTC - 5 hrs

The usefulness of those functions is one of the reason I love Railo - it has them built-in. And also an incredibly useful one for creating Queries too.
(See here: http://www.railo.ch/blog/index.cfm/2006/12/19/New-... )

Posted by Peter Boughton on Jan 16, 2007 at 03:46 AM UTC - 5 hrs

Ben - no worries at all!

Dan - Thanks for that idea. I might have to alias those functions to something shorter to achieve the readability/clarity I desire, but that is a most excellent idea. The ability to define arrays and structs inline are two of the top 3 things I'd like to see in Coldfusion. The other is a methodMissing or basically a function that gets called in case of an error.

Peter- Cool. I'll have to check that out. And clearly I need to add something to convert URLs to links and shorten them... if that address was any longer, the page would be broken =).

Posted by Sam on Jan 16, 2007 at 02:04 PM UTC - 5 hrs

"a most excellent idea"

Is that something Bill and Ted should be saying, and not me?

Posted by Sam on Jan 16, 2007 at 02:05 PM UTC - 5 hrs

Leave a comment

Leave this field empty
Your Name
Email (not displayed, more info?)
Website

Comment:

Subcribe to this comment thread
Remember my details
Google
Web CodeOdor.com

Me
Picture of me

Topics
.NET (19)
AI/Machine Learning (14)
Answers To 100 Interview Questions (10)
Bioinformatics (2)
Business (1)
C and Cplusplus (6)
cfrails (22)
ColdFusion (78)
Customer Relations (15)
Databases (3)
DRY (18)
DSLs (11)
Future Tech (5)
Games (5)
Groovy/Grails (8)
Hardware (1)
IDEs (9)
Java (38)
JavaScript (4)
Linux (2)
Lisp (1)
Mac OS (4)
Management (15)
MediaServerX (1)
Miscellany (76)
OOAD (37)
Productivity (11)
Programming (168)
Programming Quotables (9)
Rails (31)
Ruby (67)
Save Your Job (58)
scriptaGulous (4)
Software Development Process (23)
TDD (41)
TDDing xorblog (6)
Tools (5)
Web Development (8)
Windows (1)
With (1)
YAGNI (10)

Resources
Agile Manifesto & Principles
Principles Of OOD
ColdFusion
CFUnit
Ruby
Ruby on Rails
JUnit



RSS 2.0: Full Post | Short Blurb
Subscribe by email:

Delivered by FeedBurner