Count the number of arguments passed into a function.

12 views
Skip to first unread message

Gavin Baumanis

unread,
Jan 4, 2012, 11:54:59 PM1/4/12
to cfaussie
Hi there,
Let me explain what I am trying to do,

the executive summary is that I want to count the number of arguments
passed into a function.
anyFunction(), might have 10 cfargument properties assigned to it.
But if I call;
anyFunction(arg1="1", arg2="2")

Then I somehow want to be able to retrieve the value 2 (2 passed in
variables).

Why,
Because I have a getObject method.
getObject is basically a cfquery and I filter the results of the
query, based on the arguments passed in.
so if I have;
getObject(myId = 1, yourId = 2);

then it creates SQL that looks like;
select STUFF
from myTable
where 1=1
and myid=1
and yourid=1
and...(add a number of arguments here....)

If I do NOT pass in any arguments, then the SQL retrieves ALL rows
from the table.
But I want to do is;
If no arguments are passed in - create an empty object.

(we have a getAllObjects function to retrieve all rows)

maybe some code will help...

I have two snippets of code;
One is a function in a CFC, the other is some code in a CFM template
that calls the function - pretty simple.

myTestCFC.cfc:
<cffunction name="blah">
<cfargument name="text" required="false" />
<cfargument name="messageid" required="false" />
<cfargument name="queryid" required="false" />
<cfargument name="datasource" required="false" />

<cfset var local = {} />
<cfset local.length = #structCount(arguments)#>

<cfreturn local.length>
</cffunction>


test.cfm:
<cfset myReturnVal = myTestCFC.blah(text="gav", queryid=3)>
<cfdump var="#myReturnVal#">
<br />
<cfif structKeyExists(messageCFC, "messageid")>
Yes
<cfelse>
No
</cfif>

the output of this code is;
4
No

The value 4 is because blah() has 4 arguments defined.
But structKeyExists, returns false...

How can it not exist but be accounted for?
surely one of the values is wrong?

If I change the code slightly to be;
<cfset local.length = #structKeyList(arguments)#>
instead of;
<cfset local.length = #structCount(arguments)#>

Then all four arguments defined in the "stub" of the function are
listed.

So is one of the values being returned a bug?

and lastly,
How do I go about "counting" actual passed in aerguments?
(I could write another function that loops through
structKeyLists(arguments),
then do a structKeyExists[i]
and increment a counter and do my own accounting....
but it just "seems" like there should be a nicer way to do it...

As always - Thanks for any thoughts!

Gavin.

Paul Kukiel

unread,
Jan 5, 2012, 12:11:54 AM1/5/12
to cfau...@googlegroups.com
It looks like you trying to access a property ( messageId ) of the instance with

<cfif structKeyExists(messageCFC, "messageid")>

presuming messageCFC is an instance of message ?

Paul

Dale Fraser

unread,
Jan 5, 2012, 12:29:32 AM1/5/12
to cfau...@googlegroups.com

Take this simple example, there is clearly a bug in some of these CF functions

 

<cfset test(1, 2) />

 

<cffunction name="test">

      <cfargument name="a1" />

      <cfargument name="a2" />

      <cfargument name="a3" />

      <cfargument name="a4" />

     

      <cfoutput>#structCount(arguments)#</cfoutput>

      <cfdump var="#arguments#" />

      <cfoutput>#structKeyExists(arguments, 'a3')#</cfoutput>

     

</cffunction>

 

OUTPUTS

 

4

struct

A1

1

A2

2

A3

undefined

A4

undefined

NO

 

So

 

structCount counts it

<cfdump can display it

structKeyExists says it doesn’t exist

 

So it kind of half exists.

 

Regards

Dale Fraser

 

http://dale.fraser.id.au

http://cfmldocs.com

http://learncf.com

http://flexcf.com

--

You received this message because you are subscribed to the Google Groups "cfaussie" group.

To post to this group, send email to cfau...@googlegroups.com.

To unsubscribe from this group, send email to cfaussie+u...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/cfaussie?hl=en.

Gavin Baumanis

unread,
Jan 5, 2012, 12:35:08 AM1/5/12
to cfau...@googlegroups.com
Hi Paul,
 
Bad copy / pasting ....
messageCFC  = myTestCFC - sorry.....
 
<cfif structKeyExists(messageCFC, "messageid")>
 
should be
<cfif structKeyExists(myTestCFC, "messageid")>

Paul Kukiel

unread,
Jan 5, 2012, 12:36:57 AM1/5/12
to cfau...@googlegroups.com
I see what your saying now.  Yeah seams wierd

Paul

Dale Fraser

unread,
Jan 5, 2012, 12:47:24 AM1/5/12
to cfau...@googlegroups.com

This however works

 

<cfset test(1, 2) />

 

<cffunction name="test">

      <cfoutput>#structCount(arguments)#</cfoutput>

      <cfdump var="#arguments#" />

      <cfoutput>#structKeyExists(arguments, 'a3')#</cfoutput>

     

</cffunction>

 

OUTPUTS

 

2

struct

1

1

2

2

NO

 

So it seems that when you use <cfargument your semi creating a structure of arguments that kind of half exist.

charlie arehart

unread,
Jan 5, 2012, 12:54:31 AM1/5/12
to cfau...@googlegroups.com
Yep, that's an interesting challenge, Gavin. (And if anyone may have read
only the first sentence of his note and not the rest, note that he IS
already counting the arguments struct, but the issue is that because he's
using cfargument to define them, even without any default, all those defined
args appear in the struct even if no value is passed in.)

Ben Nadel has blogged on this same problem a few years ago:

http://www.bennadel.com/blog/1430-ColdFusion-ARGUMENTS-Keys-Always-Exist-Eve
n-When-Not-Required.htm

Sadly neither he nor anyone else reading it had any solution other than what
you've proposed, Gavin, doing a structkeyexist to test if there's a value
passed in.

I do agree that it could be helpful to get the value more easily, and I'm
really surprised that it's not something that's been solved (though I have
to admit I've not needed it before, but I can appreciate its value.) Perhaps
someone here will point out something we're all missing. :-)

One little tip that could help find another solution is that the arguments
scope can be processed either as a struct or an array. While
arraylen(arguments) returns the same value as structcount, but the slot in
the array for any argument not provided will be empty, and that can be
tested as of CF8 with arrayisdefined(array,index). Not really any better
than structkeyexists. Again, though, maybe thinking about it as an array
instead may give someone an idea.

Finally, I'll note that I searched the cflib.org site, and of the 55 UDFs
there that refer to "count", none seemed related to solving this problem.
Same with the 21 that referred to "arguments".

/charlie


> -----Original Message-----
> From: cfau...@googlegroups.com [mailto:cfau...@googlegroups.com] On

Dale Fraser

unread,
Jan 5, 2012, 1:08:54 AM1/5/12
to cfau...@googlegroups.com
I think it's a bug one way or another and Adobe should fix it.

structCount is INCORRECT imo shows 4 elements
dump is INCORRECT imo shows 4 elements
structKeyExists is CORRECT. It doesn't think its there.

Anything else you try to do to those elements, think it doesn't exists thus
the first 2 don't follow the same rules

<cfoutput>#arguments.a4#</cfoutput>

Element A4 is undefined in ARGUMENTS.

One way or another the behaviour should be consistant.

Regards
Dale Fraser

Kai Koenig

unread,
Jan 5, 2012, 1:21:22 AM1/5/12
to cfau...@googlegroups.com
I trust you've logged that bug?

Cheers
Kai


--
Kai Koenig - Ventego Creative Ltd
ph: +64 4 476 6781 - mob: +64 21 928 365 / +61 435 263 414
web: http://www.ventego-creative.co.nz
blog: http://www.bloginblack.de
twitter: http://www.twitter.com/agentK
--

christophe albrech

unread,
Jan 5, 2012, 2:03:23 AM1/5/12
to cfau...@googlegroups.com
Here's a silly but funny way to do it:

#structCount(arguments) - (listLen(SerializeJSON(arguments),"null") - 1)#

Dale, with your example, it goes 4 - (3-1) = 2 actual elements.

Tof

MrBuzzy

unread,
Jan 5, 2012, 8:56:29 AM1/5/12
to cfau...@googlegroups.com
Hey Bau & Co, this one's been bending my brain for a few hours now. It's an interesting thread I read it lots. Please excuse me for just rambling a bit, so I can sleep tonight.  

@Dale 
I agree StructKeyExists will return false when the key exists, but the value is null, ie;
<cfset theStruct={'theKey'=javacast('null',0)}>
<cfdump var= "#theStruct#">
<cfdump var="#structKeyExists(theStruct,'theKey')#"><!--- outputs NO --->
I *think* I agree it's a bug. But with CF that key with a null value is not very useful. It's one of those things that's existed for a long time and for good or bad, it's one reason I use IsDefined() more. Will it ever get 'fixed'? Does it really need to be? Should they or should they not change it?
It gets a bit philosophical, eh. I don't see this exact bug in the tracker, so I wonder if this is one of those issues that's been done to death. Maybe there's a definitive answer out, perhaps it's unimportant? If not it really should be logged as a bug.

@Gavin
Your issue is of course related. The cfargument tag defines the keys in the arguments collection, but your default values are undefined. When the method is invoked the arguments collection is updated NOT overwritten. This is also the case when using argumentCollection, ie;
<cfset someMethod(argumentCollection={something='something'})>
A bit annoying? Maybe. Perhaps it has a purpose. I tend to think of it as a bug. But again it's easy to work around it, as you said just count 'em up and/or use IsDefined.  
On the flip side if it gets 'fixed' it would be more difficult to iterate over the complete list of arguments. But that could be done using metadata instead I guess. 
(Funnily it's a little like bug 75806 where Sean Corfield succinctly describes the need for defaults and empty collections to always be returned when getting metadata.) 
Again, my gut feeling is it's a change in behavior that may or may not be possible and I maybe it's another one that's been discussed a lot and we missed the party :) 
Personally I would just leave out your cfargument tags for that particular method, you're not losing much.
Finally, just be aware that if your method is invoked with a null value it is indistinguishable from an omitted argument which could be a real blow to your design, ie, in CF9 these are the same; 
<cfset someMethod()>
<cfset someMethod(messageid=javacast('null',0))>

@Tof that was pretty cool! 
I think in this case, it should probably be more readable. Well, that's my excuse for such a simple solution, and I'm sticking to it :)

<cfset local.definedArgumentCount="0">
<cfloop collection="#arguments#" item="arg">
 <cfif IsDefined('arguments.' & arg)>
  <cfset local.definedArgumentCount++>
 </cfif>
</cfloop>

G'night.

Dale Fraser

unread,
Jan 5, 2012, 9:25:10 PM1/5/12
to cfau...@googlegroups.com

But the key to the struct exists J I can dump it.

MrBuzzy

unread,
Jan 5, 2012, 9:47:25 PM1/5/12
to cfau...@googlegroups.com
Yeah, so do you agree structkeyexist should return true for that key? 

It exists, but it's not defined. 

Dale Fraser

unread,
Jan 5, 2012, 9:59:14 PM1/5/12
to cfau...@googlegroups.com

Well I originally said no because

 

Accessing it other ways fails

 

But it’s clearly there, it needs to be consistant

 

The name of structKeyExists is perhaps wrong, because it really releates to the data, not the key.

Dennis Clark

unread,
Jan 6, 2012, 2:50:51 AM1/6/12
to cfau...@googlegroups.com
Unfortunately it's too late to strive for consistency at this point.

The odd behaviour of structKeyExists is due to the underlying Java implementation, the inconsistent handling of null values in Adobe CFML, and backwards compatibility concerns.

CF structs are special Java objects that implement the java.util.Map interface. The method to retrieve a value in a Map is get(key). Map.get(key) returns a Java null if the key does not exist in the map. However if the key exists but the value is a Java null, then Map.get(key) also returns null, so Map.get(key) alone is insufficient to tell whether the key exists or not. Given the behaviour of CF's structKeyExists(), it is extremely likely that Adobe implemented it via Java's Map.get(key).

The issue could be worked around by exposing Java's Map.containsKey(key), but that would expose the other two problems. CF is still a bit confused about null values. In many cases CF treats a variable with a null value as if it doesn't exist (much like a struct key with a null value). At other times it automatically converts it to an empty string. Changing structKeyExists() to return true for keys with null values would also require a sensible way for CF to handle those null values. A number of proposals have been made about this. My preference is the implementation of a proper "void" type (whose only possible value is null) in CFML.

That brings us to the third problem. There is lots and lots of legacy code that relies in the existing behaviour that has been around since ColdFusion MX. I've written <cfif structKeyExists(arguments,"foo")> more times than I can count. If structKeyExists() were changed to return true for keys with null values, a lot of that code would break. Adobe's policy for the evolution of CF has been to avoid the creation of such severe backwards-incompatibilities, and I don't see Adobe changing it's position on this any time soon.

Someone who feels passionately about it should file a bug report (if they haven't already), but I'm almost certain that Adobe will treat it as a "wontfix".

-- Dennis

charlie arehart

unread,
Jan 6, 2012, 10:51:51 AM1/6/12
to cfau...@googlegroups.com

I’ll repeat, in case the point was missed: if the concern here is that structkeyexists doesn’t do the job, note again that the arguments struct can be treated as an array as well as a struct. And the arrayisdefined function (new since 8) can test for the existence (or not) of an element in the array—and there will be no element in the array for an argument which was defined with cfargument but not passed in on the call (which was the concern originally presented). Hope that helps someone.

/charlie

 

From: cfau...@googlegroups.com [mailto:cfau...@googlegroups.com] On Behalf Of Dennis Clark
Sent: Friday, January 06, 2012 2:51 AM
To: cfau...@googlegroups.com
Subject: Re: [cfaussie] Count the number of arguments passed into a function.

 

Unfortunately it's too late to strive for consistency at this point.

 

The odd behaviour of structKeyExists is due to the underlying Java implementation, the inconsistent handling of null values in Adobe CFML, and backwards compatibility concerns.

 

CF structs are special Java objects that implement the java.util.Map interface. The method to retrieve a value in a Map is get(key). Map.get(key) returns a Java null if the key does not exist in the map. However if the <snip>

Mark Ireland

unread,
Jan 6, 2012, 6:09:19 PM1/6/12
to cfau...@googlegroups.com
OK, how about writing a UDF that just gives structKeyExists() a name that does not produce these headaches.


To: cfau...@googlegroups.com
Subject: RE: [cfaussie] Count the number of arguments passed into a function.
Date: Fri, 6 Jan 2012 13:59:14 +1100

Gavin Baumanis

unread,
Jan 11, 2012, 12:14:18 AM1/11/12
to cfau...@googlegroups.com
Hi All,
 
Just to follow up on this  - now that I am back to working on this issue...
 
And, not that I ever doubted Charlie... but a some working code is worth a thousand words...
 

<cffunction name="blah">


 <cfargument name="messageid" required="false" />
 <cfargument name="text" required="false" />
 <cfargument name="queryid" required="false" />
 <cfargument name="datasource" required="false" />

 <cfset var local = {} >

 <cfset local.mystruct.1 = arrayIsDefined(arguments, 1)>
 <cfset local.mystruct.2 = arrayIsDefined(arguments, 2)>
 <cfset local.mystruct.3 = arrayIsDefined(arguments, 3)>
 <cfset local.mystruct.4 = arrayIsDefined(arguments, 4)>

 <cfreturn local.mystruct>
</cffunction>

<cfset myStruct = blah(text="gav", queryid=3)>
<cfdump var="#myStruct#">

Gives the following;

struct
1 NO
2 YES
3 YES
4 NO


Which will solve the issue I am having, thanks Charlie.

Though I still think the implementation should be consistent across all functions.

 

Gavin.

charlie arehart

unread,
Jan 12, 2012, 5:43:31 PM1/12/12
to cfau...@googlegroups.com

Glad to help. Thanks for the update.

/charlie

 

From: cfau...@googlegroups.com [mailto:cfau...@googlegroups.com] On Behalf Of Gavin Baumanis
Sent: Wednesday, January 11, 2012 12:14 AM
To: cfau...@googlegroups.com
Subject: Re: [cfaussie] Count the number of arguments passed into a function.

 

Hi All,

 

Just to follow up on this  - now that I am back to working on this issue...

 

And, not that I ever doubted Charlie... but a some working code is worth a thousand words...

 

<cffunction name="blah">
 <cfargument name="messageid" required="false" />
 <cfargument name="text" required="false" />

<snip>

Reply all
Reply to author
Forward
0 new messages