Yeah, I'll write some stuff up about CF.Objective() shortly, but I need to plan that a bit more before I put pen to paper. This is a quick no-brainer (so playing to my strengths ;-).
In ColdFusion 9, script-only CFCs were introduced. This is one of my favourite additions to CFML... tag based components and the tag-based syntax is a very clunky approach to code that - almost always - won't be having anything to do with mark-up.
One syntactical challenge Adobe were faced with is how to reflect the more "meta" of function and argument definitions, eg stuff like the
hint
, output
, roles
etc. The direct tag -> script syntax was pretty clunky:<cffunction name="f" output="false" roles="special" hint="Does some stuff">
</cffunction>
Becomes:
function f() output=false roles="special" hint="Does some stuff" {
}
One expects clunky verbosity in tags, but it's a shame to have to write code like that in script.
For metadata-only type attributes -
description
, displayname
, hint
, etc - a suitable solution is to use a Javadoc style annotation, eg:/**
* @hint This appears in the API docs for the function
* @description This is a description
* @displayName This is the displayName
*/
function hasMetadata() output=false roles="special" {
}
When looking at the metadata for the function, we see this (ColdFusion 9):
array | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 |
|
And on Railo, this:
Array | ||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
|
Note that Railo seems to not support the description attribute here.
Just before I go on, there's one thing to note here. This is fine:
/**
* @hint This appears in the API docs for the function
* @description This is a description
* @displayName This is the displayName
*/
This is not fine:
/**
* @hint This appears in the API docs for the function
* @description This is a description
* @displayName This is the displayName
*/
The difference? Well it shows when I look at how ColdFusion processes that metadata:
array | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 |
|
Notice how that it specifically looks for a space between the attribute and its value. Just "whitespace" doesn't count. So I cannot tab-align the values (which I'm inclined to do). Obviously (/predictably) Railo is not tripped up by this. It just works.
Anyway, as I was saying...
That's all fine, but what about the non-metadata additional params, eg:
roles
, output
, etc which actually change runtime behaviour? These don't belong in a comment - comments should not change how code runs because they're comments, so the only "appropriate" place for these is to use the "tag styled" approach, as demonstrated earlier: as attribute/value pairs on the function definition.It's significant to point out here that Railo have taken the sensible route here - and is at odds with ColdFusion - and does not support anything in the Javadoc block other than the metadata-type attribute values such as hint and display name. Once cannot specify "functional" parameters there such as output, access, roles etc. Any setting that impacts how code will run must be in the function declaration, not in the Javadoc block.
Here's an example:
// ScriptBased.cfc
/**
* @extends Parent
*/
component {
/**
* @access private
*/
function privateFunction(){
}
/**
* @returntype boolean
*/
function booleanFunction(x){
return x;
}
}
// Parent.cfc
component {
function parentFunction(){
}
}
// test.cfm
o = new ScriptBased();
writeDump(getMetadata(o));
safe(function(){
writeOutput("Running parentFunction()<br>");
o.parentFunction();
writeOutput("OK");
});
safe(function(){
writeOutput("Running privateFunction()<br>");
o.privateFunction();
writeOutput("OK");
});
safe(function(){
writeOutput("Running booleanFunction()<br>");
o.booleanFunction(x=["not boolean"]);
writeOutput("OK");
});
function safe(f){
try {
f();
}catch(any e){
writeOutput("[#e.type#] #e.message# (#e.detail#)");
}finally{
writeOutput("<hr>");
}
}
On ColdFusion 11 we get this:
struct | |||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
EXTENDS |
| ||||||||||||||||||||||||||||||||||
FULLNAME | blogExamples.railo.bugs.metacomments.ScriptBased | ||||||||||||||||||||||||||||||||||
FUNCTIONS |
| ||||||||||||||||||||||||||||||||||
NAME | blogExamples.railo.bugs.metacomments.ScriptBased | ||||||||||||||||||||||||||||||||||
PATH | C:\webroots\blogExamples\railo\bugs\metacomments\ScriptBased.cfc | ||||||||||||||||||||||||||||||||||
TYPE | component |
Running parentFunction()
OK
Running privateFunction()
[Application] The method privateFunction was not found in component C:\webroots\blogExamples\railo\bugs\metacomments\ScriptBased.cfc. (Ensure that the method is defined, and that it is spelled correctly.)
Running booleanFunction()
[boolean] The value returned from the booleanFunction function is not of type boolean. (If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible.)
So CF has read the comments, and its behaviour changes accordingly.
Railo does this:
Array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 |
|
Running parentFunction()
[expression] component [ScriptBased] has no function with name [parentFunction] ()
Running privateFunction()
OK
Running booleanFunction()
OK
Because Railo does not respect the functional attributes when specified in a comment, it does not consider ScriptBased.cfc to extend Parent.cfc, it does not consider
privateFunction()
to be private, nor booleanFunction()
to be Boolean.I mention this because it seems to have caught someone out who is migrating from ColdFusion to Railo.
I'm all for Railo - on the whole - emulating ColdFusion's CFML. But when the ColdFusion approach is just stupid, then I'm OK fro Railo not to be stupid too.
That's it. Just tuck this into the back of your mind somewhere, so it doesn't catch you out. Don't specify stuff that impacts how your code runs in comments. Even if ColdFusion allows it. It's just dumb.
--
Adam