Tuesday 10 September 2013

CFML: Way to make me feel thick, Sean... by explaining <cfparam> to me

G'day:
OK, it's not about <cfparam>, but relating to its CFScript-ready chum: param.

Yesterday I wittered on about things I don't like in CFScript, and one example I used of "how not to do it" was the <cfparam> tag's CFScript equivalent, which seemed to be just "<cfparam> without the '<cf' and '>'":

<cfparam name="foo" default="bar" type="regex" pattern="[a-z]+">

Becomes:

param name="foo" default="bar" type="regex" pattern="[a-z]+";

Sean quickly pointed out that that is unnecessarily verbose and disagreeably ugly, but the unnecessary part is because... actually it's not necessary. Because one doesn't need to be so verbose with param. These all work:

param favouriteNumber;
param favouriteNumber=3.1415;
param numeric favouriteNumber=1.1414;


That is much better syntax. It doesn't match anything else in CFML that I'm aware of, but it's quite neat so I'll forgive that.

I had a look around last night, and I could neither find reference to this in the docs, and only actually one place that mentioned param at all, which was the "what's supported in CFScript" page of the docs. However looking again this morning, I've spotted this page too: "Tags" (the irony being that the info about a non-tag is on a page entitled "tags" is not lost on me). Adobe really need to lift their game when it comes to documenting CFScript: it is not longer a second-class citizen when it comes to CFML, yet it's still treated that way in the docs. The <cfparam> page should detail the script equivalent, and each CFScript statement / keyword / construct should have its own separate page (again, with a link across to the tag equivalent).

Anyway, those docs on the "Tags" page say this:

cfparam: param [type] name [=defaultValue];
The param attribute can now take any number of name=value pairs. Param can also take all the attributes of <cfparam> as name-value pairs.For example:

<cfscript>
param name="paramname" default="value" min="minvalue" max="maxvalue" pattern="pattern"
</cfscript>
So that's good. Wrong page to document it on, but it's a start. I'm also not sure what the sentence "The param attribute can now take any number of name=value pairs." is supposed to mean?

I tried a few more combos of <cfparam> tag attributes in the script equivalent, and had varying results.

This works on ColdFusion:

param URL.favouriteNumber;

But it errors on Railo:

missing name declaration for param

(This is on 4.1.1.003, which I believe is the most up-to-date version of Railo).

Note: unscoped variable names on Railo work fine, just scoped ones do not, it seems.

Neither ColdFusion nor Railo permit this:

param URL["favouriteNumber"];

That's a legacy of how <cfparam> (and the underlying setVariable() function) works, I guess. However it should work fine.

This works on Railo:

param regex favouriteNumber pattern="[1-5]+";

(nice!)

But errors on ColdFusion (tested on 9.0.1 and 10.0.11):

Attribute validation error for function PARAM.

It does not allow the attribute(s) REGEX,NUMBER. The valid attribute(s) are DEFAULT,MAX,MAXLENGTH,MIN,NAME,PATTERN,TYPE.


The error message itself is a bit wrong, because param is not a function. It also seems like the parser is screwing up, as it doesn't understand that "number" is the param name, not an "attribute", per se.

This prompted me to try a range on Railo:

param range favouriteNumber min=41 max=43;

Worked fine. Coolness! Predictably - based on the previous error message - ColdFusion does not support this. I consider this a bug, and will raise it accordingly.

OpenBD, btw, supports none of this.

Finally Railo also correctly supports this:

param string loginId maxlength=50;

(I didn't even know <cfparam> / param supported a maxlength attribute until just now either!)

So that's cool syntax, but it's buggy on all three platforms:

  • Railo: doesn't work with scoped variables. This is probably the worst of the bugs (RAILO-2605).
  • ColdFusion: doesn't support regex or range or maxlength (3629223).
  • Railo and ColdFusion: hamstrung by out-of-date syntax rules, so cannot param associative-array-syntax param names (CF: 3629224; Railo: RAILO-2606).
  • OpenBD: doesn't support it at all.

I'll raise bugs for the Railo and ColdFusion issues (and cross-ref back to here once I've done it). I don't care about OpenBD (and they don't care about CFML compatibility either), so...  well I won't bother raising a bug with them about this.

Here's my closing question... did you know about this syntax? I've seen a lot of code in my years, and never once saw this before. So am I a bit ignorant, or was this hidden away from most other people too?

--
Adam