Thursday 16 April 2015

Lucee 5 beta: tag attributes fix

G'day:
Here's another quick one. I'm waylaid at work and have a few minutes to spare between one hold-up and the next one.

One of the most stupid things about the way CFML tags are processed is that in this tag:

<cfinvoke method="f" arg1=m arg2=n>

The tokens m and n are treated as strings. IE: the literal strings "m" and "n".

Clearly they're not strings, as strings have string delimiters around them, ie: single or double quotes.

If you don't believe me, here's an example:

<!--- demo.cfm --->
<cfset m=1>
<cfset n=5>
<cfinvoke method="f" arg1=m arg2=n>

<cfscript>
    function f(){
        writeDump(arguments);
    }
</cfscript>

(sorry if all the tags hurt your eyes, but it's a tag-only issue this one).

Anyway, this outputs:

struct
ARG1m
ARG2n

To make ColdFusion (and, indeed, Railo or now Lucee) understand those are variables, one needs to resolve them with pound-signs:

<cfinvoke method="f" arg1=#m# arg2=#n#>

The only time one should need to use pound-signs is when there's ambiguity as to whether the text is a CFML expression or just a string, namely:

  • in the body of a CFM file;
  • within a string.

There ought be no ambiguity here because for m and n to be strings, they'd need to actually be in quotes! And there is no ambiguity as to whether it's free-text or whether it's CFML, because it's in a bloody CFML tag!!

This bug has been part of CFML forever, as far as I know.

Anyhow, Lucee 5 has fixed this.

On the default configuration of Lucee 5, running a CFML file, behaviour is still the same as it always is. However there's a setting in the administrator to disable default behaviour:


Unchecking that box results in those variables actually being seen as variables, so the output is:

Scope Arguments
arg11
number1
arg22
number5

Note that this is a compile-time setting, which means it will not take effect until the file in question is next compiled. So to see it in action, you will need to touch the file so it compiles next time it's requested. Despite the setting being in the language/compiler section of the settings, I did not click to this at first, and I got caught out. The ramifications of this is that this setting can't be made in Application.cfc, as those are only runtime settings. I hope when the final docs are released, this is made explicitly clear.

One bonus is that using the .lucee dialect, the behaviour is fixed by default. There's not setting to change. Here's the same code in .lucee dialect:

<!--- demo.lucee --->
<:set m=1>
<:set n=5>
<:invoke method="f" arg1=m arg2=n>

<:script>
    function f(){
        writeDump(arguments);
    }
</:script>     

This has the same output as the second example above.

My challenge with these compiler settings Railo / Lucee offers is that pretty much one can't actually use them. We - CFML devs - are never only running our own code these days (we're running FW/1 or Taffy, or SomeSortOfBox), and that code all has to be written for default behaviour. Which pretty much means the compiler settings need to be default (just for safety and stability sake), which means our implementation code also needs to only leverage default behaviour. I think the idea of having these "better" settings was an admirable concept, and if our apps could be compiled separately to vendor apps, and with separate compiler settings then they would make sense. But I think this is seldom how CFML code is used, so it's lovely to write blog articles about, but not so useful in real life.

However if this .lucee dialect fleshes out a bit more, it's able to make a completely new start and not worry about legacy code. So no compiler settings, just different & improved behaviour by default. That's something to look forward too, I think.

Anyway... I'm still in the office but have finished my calls so can go home now. And much as I like typing this nonsense, I prefer dinner and just not being at work that much more. Hard to fathom, I know.

Righto.

--
Adam