CFML is a tag based language. When tags need arguments or options passed to them, they are passed as attributes. This is an integral part of what makes CFML so easy and so productive. But sometimes, having to pass attributes can be a hindrance. Consider a simple example, a where you sometimes just need basic attributes (NAME and DATASOURCE perhaps) but other times want additional optional attributes (like USERNAME and PASSWORD). There is no way to conditionally include attributes in a tag, and so you end up having to write code like this:


...



...


It’s just an example, but it’s not pretty at all. And this same is true if you conditionally want to add query caching, or specify an SMTP server in , and so on.
Scorpio solves this problem in the simple and elegant fashion we’ve come to expect from ColdFusion. In Scorpio you can pass all tag attributes as a single structure, an ARGUMENTSCOLLECTION. Here is a simple :




...

As structure members can be added conditionally, passing optional attributes becomes a simple matter of conditionally adding members, as seen here:











...

This new syntax can be used by all sorts of tags, including , , , , , , and many more.

30 thoughts

  1. Ben – you need to increase the font size for your code output in your blog. It is barely readable. We’re looking forward to your visit in Kansas City at KCDevCore.

  2. Michael,
    Yep, all CFFORM tags (including CFFORM, CFINPUT, CFSELECT, etc.) and CFQUERYPARAM support this syntax. In fact, it is supported by just about everything except from flow control tags (CFIF, CFCASE) and variable assignment tags (CFSET, CFPARAM) and tags like CFOUTPUT.
    — Ben

  3. Awesome addition! Is there any plan to add some kind of short syntax for creating arrays and structures? Kind of like in javascript where you can do something as follows:
    var struct = { title: ‘Hello’, content: ‘World’ };
    It just gets pretty repetitive so have to do a bunch of cfsets, ArrayAppends(), etc.

  4. Ben:
    I’m curious why this feature uses argumentsCollection as opposed to the existing argumentCollection shortcut that can be used to pass arguments to a cfc call?
    Is there a reason they’re different?

  5. Ben,
    Maybe Jim is using FF under Linux. I have been getting set-up under Linux (PCLinuxOS). One of the things I noticed is the code blocks on my blog being quite small. If I have trouble reading anything I just use CTRL-+ and CTRL–.

  6. Ben, Great feature, looking forward to using it!
    Question – Shouldn’t it be AttributeCollection or AttributesCollection instead of ArgumentsCollection? Or like Todd Sharp said, the existing variable we’re already used to typing, ArgumentCollection. Thanks for the teaser – see you on Wednesday!

  7. Ben,
    Can you mix the two types, i.e. still use the NAME parameter but pass in the others like DSN, USERNAME, PASSWORD, etc via the ARGUMENTSCOLLECTION parameter? Same question for other tags too. I would hope that an argumentscollection member would be used only if there were not a direct parameter specified.

  8. Mathew, no, if you use the ARGUMENTSCOLLECTION then it must be the ONLY actual tag attribute. That way there is no ambiguity over which to use if the same attribute is defined in both places.
    — Ben

  9. Hi Ben, this looks to be a great feature.
    I would like to stress however that this feature remain consistent with both cfmodule and cfinvoke. With both of them, you can pass attributeCollection and argumentCollection attributes respectively along with normal attributes (and cfinvokearguments as well).
    Where I see this losing a lot of value is in the example you posted. I would very likely cache the username and password for cfquery calls in a structure in my application as I do now, but using this new method to pass them in. The problem comes when I want to have different names for all my query and caching when necessary. Having to modify or copy the struct in these cases completely voids the feature.
    Here are the docs I found on the precedence of arguments, which make great sense to me as they are in order of how explicit the arguments are:
    Using hybrid means of passing cfinvoke arguments (explicitly stated precedence)
    http://livedocs.adobe.com/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?href=00001051.htm
    Using hybrid attribute passing with custom tags (coded in the example)
    http://livedocs.adobe.com/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?href=00001077.htm
    Thanks for sharing and I’m excited to see your presentation tonight at the DFW CFUG!
    Mike Kelp

  10. Ben, this is a great addition.
    Regarding the font size issue, any font size set below 0.8em becomes illegible in browsers such as Opera and FF on the Mac. If you change the font-size value from 0.7em to 0.9em in the .code declaration in the style.css file, the fonts will be readable cross-platform.
    Thanks again for telling us about argumentscollection!

  11. Thomas Messier raised the question as to whether we can do:
    var struct = { title: ‘Hello’, content: ‘World’ };
    Well, let me tell you that I saw that last night at Ben’s DFW CFUG presentation. You can also do arrays that way too with:
    var array = ["First", "Second", "Third"];
    (I think the syntax is right there). So, yes it will be available in Scorpio if I understood it right. I remember Ben saying that you ought to be able to take existing java declarations and just copy them in – so I guess they have the syntax the same. Good idea if you ask me!
    Steven

  12. This absolutely rules. As small as it seems to be, it’s the kind of thing that saves developers tons of time because we use these functions all the time. I’m thrilled to hear it was added, it shows that the people at Adobe are really paying attention to the things that matter!

  13. I think Mike Kelp is correct in that you need to be able to use attributeCollection AND have extra attributes specified as well. As mentioned, being able to setup a DSN struct isn’t very useful if you can’t easily specify a query name.
    From a precedence standpoint, I’d grab the attributeCollection first, if it exists, then apply any additional attributes that may be present. That seems intuitive to me, and I’d rather have the possibilty of a slight bit of confusion, which can be cleared up by reading the documentation, as opposed to requiring the developer to write addtional lines of code to do structCopys and extra struct assignments just to set a query name.
    Further, it’s pretty well established that tags (and custom tags) have attributes, and some tags already have an attributeCollection. CFFunctions, OTOH, have arguments. Please don’t confuse the issue, and use attributeCollection for the new tag feature.

  14. Ben,
    With the JSON syntax for the structs/arrays/etc, is there a native tag that will go the other direction? i.e. tag a CF struct and produce json text? Maybe a cfjson tag that works just like cfwddx, but works with json syntax?
    I love the simplicity of wddx, but prefer the smaller raw data size of the json syntax.

  15. Looks like I got a discussion started in the wrong blog post. Sorry Ben! Steve, I think while the syntax is JSON-esque, it’s not exactly JSON, you don’t use colons for objects/structs, for example. Having said that, native JSON support would be great. Meawhile you can use CFJSON, an open source project at http://www.epiphantastic.com/cfjson (which I maintain), it does exactly what you said.

  16. Absolutely Thomas, I use it all the time and love it. So much so that i think it should be native to CF.

  17. Man, this is another cool feature… I can see it coming in handy for sure! Especially on the cfquery tag.
    DAMN IT I’m on my 4th attempt at this captcha.

  18. I am not sure if anyone else has pointed this but is there is a reason that this special attribute is called argumentCollection and not attributesCollection. attributesCollection is more consistent with how attributes can be passed to regular custom tags

  19. We had an interesting discussion at the triangle adobe user group meeting last night about this regarding whether or not named arguments should override arguments specified in the argumentcollection, or if they should be ignored, or if they should cause an error.
    Tim and Adam took a straw poll, and we mostly voted for "override"… that way you can use an argumentcollection for "default" arguments but you can still override certain arguments if you need to or want to. Like you might have an argumentscollection stored in the application scope that you use as a default for cached queries, but maybe you want to change one attribute for a certain query, like how long a query is cached…
    Damn it, I can *NEVER* get the captcha right the first time on this blog… how about a third time… nope let’s go for four… five..?

  20. Just a footnote for the fellow slow witted. It was AttributeCollection they went with in the end:
    So the cfc query code abbreviates neatly to:
    <cfquery ATTRIBUTECOLLECTION = "#REQUEST.query_parameters#" name="getData">
    In the Application.cfc in the onRequestStart function:
    <cfscript>
    REQUEST.query_parameters = StructNew();
    REQUEST.query_parameters.datasource = THIS.DataSourceName;
    if(THIS.database_uses_password){
    REQUEST.query_parameters.username = THIS.DB_Username;
    REQUEST.query_parameters.password = THIS.DB_Password;}
    </cfscript>
    I set all my variables on cfinclude page i.e.app_parameters.cfm using the THIS scope for users with different setups. i.e.
    THIS.DataSourceName = "dsn_name";
    THIS.database_uses_password = True;
    THIS.DB_Username ="db_username";
    THIS.DB_Password ="db_password";
    Being explicit as I went off on a wild goose chase with this issue. Might save some fellow travellers some time.

Leave a Reply