Iterating Over Function Arguments Using CFLoop In Lucee CFML
In my previous post on flattening arrays in ColdFusion, I mentioned that the arguments
scope in a Function body acts as both an Array and a Struct. This is a truly great feature of ColdFusion; but, iterating over such a dynamic data structure can be confusing at times. Luckily, ColdFusion also gives us the highly dynamic CFLoop
tag. We can use CFLoop
to iterate over the arguments
scope using either Array iteration or Struct iteration.
To see this in action, I've create a function with two named arguments; but, I'm going to pass-in four arguments. Then, I'm going to iterate over the arguments
scope twice: once as a Struct and once as an Array:
<cfscript>
testArgIteration( "aye", "bee", "see", "dee" );
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
/**
* I test Function argument iteration using the CFLoop tag.
*
* NOTE: I have TWO NAMED ARGUMENTS defined, but I'm passing-in FOUR arguments.
*/
public void function testArgIteration( a, b ) {
// Using CFLoop to iterate over the arguments scope as a Struct. In this case, the
// "key" is either the NAME of the argument, if it exists; or, the INDEX of the
// argument if it is unnamed.
loop
key = "local.key"
value = "local.value"
struct = arguments
{
dump({
key: key,
value: value
});
}
// Using CFLoop to iterate over the arguments scope as an Array. In this case, the
// "key" is ALWAYS the INDEX of the argument, regardless of whether or not the
// arguments are named.
// --
// NOTE: We could have use the attributes "key" and "value" here as well, and it
// would have worked the same. I am opting for "index" and "item" since they feel
// more Array-appropriate.
loop
index = "local.index"
item = "local.item"
array = arguments
{
dump({
index: index,
item: item
});
}
}
</cfscript>
Notice that when I am providing the arguments
scope to the CFLoop
struct
attribute, I'm using the key
and value
attributes for iteration. And, when I provide the arguments
scope to the CFLoop
array
attribute, I'm using the index
and item
attributes for iteration. This difference in attribute selection isn't strictly necessary; however, I think it makes the code more clear.
Now, when we run this ColdFusion code, we get the following output:
As you can see, we were able to iterate over the arguments
scope as both a Struct and as an Array! Note that when treating the scope as a Struct, if we run out of "named arguments", the "index" variable will be the numeric offset of the argument.
The ColdFusion Function is a very dynamic, powerful construct in the CFML world. In fact, I listed "Named And Ordered Arguments" as one of the many reasons to fall back in love with modern ColdFusion. The arguments
scope is certainly part of that power. And, the more we understand how to use the arguments
scope, the better we can be at leveraging this great power.
structEach()
and arrayEach()
Epilogue on It's also possible to iterate over the arguments
scope using structEach()
and arrayEach()
. Frankly, I forgot these functions even existed since I moved to using member methods as often as possible. That said, at least in Lucee CFML, when I use arrayEach()
, the "index" provided to the callback is the argument name, not its index.
Want to use code from this post? Check out the license.
Reader Comments
What I truly wish would get added to CFML? Function overloading. That would be awesome. Right now, you can at least use the "default" attribute on an argument, and use cfparam, as well.
But true detection of argument types and having CFML call the appropriately flavored function would be great. But the pre-compiler would also have to recognize duplicate function signatures.
Even better would be to maintain the fuzziness of argument types, and perhaps specifically indicate a given function should be inspected for overloading.
@Will,
I go back and forth on this idea of differentiating function signatures. I think there are definitely times when it would be great. But, then, I'll go and look through the Lucee CFML code (written in Java) and there's like 8 different versions of the
call()
method all with different types of arguments, and it feels a bit overwhelming to wrap my head around what is available.That said, it would probably be kind of crazy to have 8 entirely differently named functions for the various combinations of arguments as well 🤣
All to say, I'm definitely curious to see what that would be like. But, it could also be a foot-gun as well.
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →