What are valid characters for ColdFusion user-defined function names? - coldfusion

A little background: I'm working on a project converting a webapp in another scripting language into ColdFusion. One issue I'm having is that the old technology has some function names that are the same as functions in CF, but work slightly differently. Unfortunately, in most cases I need the old functionality, so I'm planning to write my own functions.
To cause the least pain in converting the code, I was planning to prefix each function with a character not usually used in function names, e.g., $val().
I know that $ and _ are valid in function names. Are any other characters I can use? I ask because I know that some frameworks out there use this convention and I don't want to run afoul of any of those in future development. Is it unreasonable to use multiple characters this way, e.g., $_val()?

Seems reasonable to me to use $_ as a prefix. Of course, you also might want to consider giving your functions a custom 'namespace', via either inclusion in a custom scope structure like 'UDF', yielding a function named like 'UDF.val()'; also, you could package them up together in a CFC, and access them as component methods. Either way, you would be safe from name conflicts.
edit
To test the comment you just made regarding custom functions with the same name as the built-in function, I made a little test to see if that's true. It appears that you actually can build functions with the same name as the built in ones, if they are within a custom scope:
<cffunction name="foo">
<cfreturn "bar">
</cffunction>
<cfset udf = {}>
<cfset udf.IsDefined = foo>
<cfoutput>#udf.IsDefined()#</cfoutput>
This code outputs "bar".
Or, if you like the CFC approach:
foo.cfc
component {
function IsDefined()
{
return "blah";
}
}
And the invoking code:
<cfset udf2 = createObject("component", "foo")>
<cfoutput>#udf2.isDefined()#</cfoutput>

Related

Best practice to explicitly scope a cffunction defined in cfm

I understand that in ColdFusion, explicit scoping is a Good Thing. Since learning this, I try to explicitly scope all variables, even for variables like queries, for example, <cfquery name="local.myQuery"> or <cfquery name="variables.myQuery">.
My question is how to do explicit scoping when defining a function inside a .CFM page, which will be used only on the same page. Can I do <cffunction name="variables.myFunction"> or something similar?
The best practice would be to take that function out of the cfm page and put it into a cfc class, then create an instance of the class from your page and use it.
Everything else will eventually lead to tears. Coldfusion will throw an error if you try to define a function with the same name twice (so if you ever replicate this function in some other cfm that includes or is included by this page, it will crash).
Roughly speaking, this should be your Thing.cfc file:
<cfcomponent>
<cffunction name="myFunction">
</cffunction>
</cfcomponent>
and this should be your cfm:
<cfset thing = new Thing()>
<cfset thing.myFunction()>
myFunction will be scoped only to the Thing class, and you will be able to define a function of the same name in other classes, or even override it in descendant classes.
Posting my own answer with what I've found so far. The link from #Ageax's comment led me to this ColdFusion documentation on Specifying the scope of a function. It says:
When you define a UDF, ColdFusion puts it in the Variables scope.
You can assign a UDF to a scope the same way you assign a variable to a scope, by assigning the function to a name in the new scope. For example, the following line assigns the MyFunc UDF to the Request scope:
1: <cfset Request.MyFunc = Variables.MyFunc>
The way I understand this, it means that I should simply use <cffunction name="myFunction"> to define the function, but I should use explicit scoping when calling it, like variables.myFunction().
Despite the fact that functions in ColdFusion are able to live in different scopes (default is variables) you should not change that or play with it. Just use components to apply encapsulation or leave then in the variables scope. If you try to define a function with the same name (in the same .cfm or in included ones), you will get an error and that should be fine, so you can't overwrite a function like that.
You should scope the variables inside a function. You don't do that scoping the name of the function but scoping the variables inside then. Good practice would be using the local scope or the var prefix.
<cffunction name="foo">
<cfset var a = 123>
<cfset local.b = 345>
</cffunction>
In Lucee you can define globally the whole scope of a function using localmode="modern"
function foo()localmode="modern"{...}

Any way to enforce a property's type in a CFC?

I'm experiencing some weird typecasting issues here, not specific to Lucee (also in Railo). Could be that I'm just missing some crucial point here though...
I have a component:
<cfcomponent output="false">
<cfproperty name="thisId" type="String" default="-1" />
<cfproperty name="thatId" type="String" default="-1" />
</cfcomponent>
Both properties are clearly typed as strings. I would expect that when I try to set an object or a number to one of these, the code would return an error.
But, seeing as I'm used to cfml doing the typecasting for me by now, I never thought twice about the fact that setting a number here is no problem at all. I was in fact under the assumption that all number I would try to set here would be cast to strings for me.
It seems this is not the case though.
After implementing some REST calls that contain derivatives of these components in the form of a serialized struct, I onticed that some where included as an integer and some were included as a string. When I noticed that, I dumped out the component itself and notice that setting a number where a string was expected as a property, the typing had been overwritten as a number.
The fact that Railo / Lucee still validates is in my opinion beyond useless. Either validate strict typing and throw an error / pass in a correctly typed variable, or validate loose typing and convert to the type the CFC is expecting if that is possible.
Railo / lucee implemented loose type validation here, but still decides to pass in the variable in its original type, not what the cfc expects per sé.
Seeing as I don't want to be typecasting every number to a string right now, is there a simple oversight here that could salvage my typing?
(I've already posted this in the Lucee mailing list, but without any results, just people confirming what I already said / disregarding the possibility that this is not expected behaviour.)
update (as asked by Adam):
What I see is the following (in my cfc component described above):
<!--- setting a string returns a string afterwards, as expected since the property is a type string initialy --->
<cfset componentName.setThisId('1') />
<cfset local.thisIsStillAString = componentName.getThisId() />
<!--- setting a number returns a number, which means we can no longer assume the property is a string, as it was initially set up --->
<cfset componentName.setThatId(12345) />
<cfset local.thisIsNoLongerAString = componentName.getThatId() />
In both cases I would expect that either:
- the input variable would get strictly evaluated as a string, which means that the second example would raise an error, seeing that it is actually a number
- the input variable would get loosely evaluated as a string, but would be cast to a string when passing the evaluation, which would mean that the second example would pass but would ultimately return a string, no longer a number.
In any case I would expect the property's original typing to be preserved, instead it gets changed to whatever type you're trying to set, as long as it passes the current loose evaluation.
As I understand it, the built-in accessor setters will do automatic type-validation, but will only do casting where necessary and possible.
Numeric/string/date/boolean values are all considered "simple", which is why the numeric data is passing the "string" type-validation. Therefore, because it passed the validation, the casting is skipped. On a personal note, I would prefer if it did more rigorous validation, but that's an issue for the bugtracker.
Now, if you must ensure that only actual string data can make its way into those properties, you can override the generated setter for the property to do more rigorous type-casting and/or validation (I've tested this only on Lucee):
/** Example.cfc */
component accessors=true {
property type="string" name="thisId";
property type="string" name="thatId";
public function setThisId(required string newId) {
// convert numeric value to string value
if (isNumeric(newId)) {
newId = toString(newId);
// throw an exception for non-string/numeric values
// !isSimpleValue() is a catch-all btw, structs and arrays will
// be prevented by the "newId" argument's type hint
} else if (isBoolean(newId) || isDate(newId) || !isSimpleValue(newId)) {
throw(message="Invalid value specified for thisId");
}
variables.thisId = newId;
return this;
}
}
var example = new Example();
example.setThisId(54321);
example.setThatId(54321);
writeoutput(serializeJson(example)); //{"thisId":"54321","thatId":54321}
// throws exceptions:
example.setThisId(true);
example.setThisId({});
Finally, getting back to the "casting where necessary and possible" part. For the given example, if you were to try passing a component instance to the setThisId() method, it fails the type-validation step, meaning type-casting is necessary for the operation to succeed. So then the value is checked for the possibility of type-casting. If the component (and this only works on Railo/Lucee) has a _toString() "magic method" defined, then type-casting is possible. Since it is possible, the component is then cast to a string, and the result then passed into setThisId(). If that magic method is not defined on the component, it is not possible to do type casting, and an exception is thrown. Similarly for structs/arrays, type-casting is necessary, but not possible as there is no automatic serialization defined for those types, thus resulting in an exception being thrown.
TL;DR
You can override the setter accessor to do more rigorous type-validation/type-casting.
To enforce them as string (not array nor struct), use accessor=true together with your <cfproperty>'s and use setters.
However, if you're talking about SerializeJSON() treating strings of numbers as integers, that is not something type="string" can enforce. It has to do with the behavior of the SerializeJSON() function. If you really want to enforce them as string, try https://github.com/bennadel/JsonSerializer.cfc

CFWheels - Should I be locally scoping my Wheels actions?

Say I have a very simple controller like so:
<cfcomponent extends="Controller">
<cffunction name="hello">
<cfset time = Now()>
</cffunction>
</cfcomponent>
In straight ColdFusion / Railo, I would be locally scoping all variables within this...but every wheels example I see does not.
This is probably going to earn me the dumbest question of the year award, but it was something I was thinking about, since nobody ever seems to demonstrate their Wheels code scoped correctly?
I would write it as follows:
<cfcomponent extends="Controller">
<cffunction name="hello">
<cfset local.time = Now()>
</cffunction>
</cfcomponent>
I am just not sure if Wheels perhaps does something to remedy this regardless, and that's why I see what I do everywhere...or is it just a case of bad programming?
Thanks!
Mikey
Yes, you should be scoping it.
In your first example, you are (by not scoping) in most cases setting variables.time, which is local to the component instance, not to the function - if this is intended as a function-local variable (i.e. local.time) but is in the component's variable scope, and that component is shared/persisted, this may cause issues (though perhaps ones that only reveal themselves under heavy load).
If putting the variable in the variables scope is deliberate, it should still be explicitly scoped (as variables.time) otherwise it may cause issues if used on a Railo server with the localmode setting enabled.
Due to a cfWheels design decision (see links in comments), putting variables in the variables scope is required to pass variables to the view, even though they may technically be local to the function/view. (The controller instance lives for a single request, avoiding the issues this normally entails.) As mentioned in the previous paragraph, the localmode setting (described below) means it is still recommended to explicitly scope when you are not in control of all servers the code will be deployed to.
Railo's localmode setting
Railo (since v1) has had an admin setting called "localmode" which defines whether assigning an unscoped variable will go to the local scope, rather than the component's variables scope - making explicit var/local scoping not required (if you know your code will only be run on Railo servers with that setting enabled).
Since that setting is off by default, and ColdFusion does not have such a setting, cross-engine-compatible code should always scope such variable assignments to avoid this being an issue.
It depends. If you want the variable to be shown in the view, scope it to variables. If you want the variable to be only in the controller, scope it to local.

How to put UDF library into the APPLICATION scope?

I am using ColdFusion 9.0.1.
Right now, we are including our UDF library in the onRequest() method in our application.cfc. Here's how we include it:
<cfscript>
// INCLUDE LIBRARY
include "udf/udf_library.cfm";
</cfscript>
I am wondering if there is a way to put the entire library into the APPLICATION scope so that it's created just once. Would we do this the same way as we put our orders.cfc into the APPLICATION scope, like this:
APPLICATION.AppInfo.objOrders = createObject("component", "globaladmin.orders");
Should the UDF library be converted to a CFC to make this happen?
How would we reference the function in the CFC?
Currently we call the UDF functions with no fuss, like this:
<cfscript>
createButton("Canada Postal Codes", "ShowSection", "ShippingCanadaPostalCodes");
wrapCell(Buttons);
wrapRow(Cells, "TableSubHead"));
</cfscript>
It would be really ugly to have to add "APPLICTION.AppInfo" before each function.
So, would there be any advantage to moving the UDF library to the APPLICATION scope or loading it only once somewhere else?
I think scoping your UDFs is a good idea. As it is you just have them as part of the REQUEST scope, so there's room for name clashes if methods of the same names are declared in .cfm pages in other parts of your application.
If you do add them and object in the APPLICATION scope, in onApplicationSart() for instance, then you'll have to be aware of thread safety issues. Presumably your UDFs are fairly self contained, so your APPLICATION scoped object won't hold any internal state as such, so you should be safe enough in that respect.
If you just want it created once then add your functions to a CFC and create it in your Application.cfc's onApplicationStart() function, assigned to the APPLICATION scope as you've described above.
Should the UDF library be converted to a CFC to make this happen?
YES
How would we reference the function in the CFC?
APPLICATION.AppInfo.yourObj.createButton("Canada Postal Codes", "ShowSection", "ShippingCanadaPostalCodes")

What is the difference between using cfinvoke and createObject to run a component function?

In my company's code, I've often seen component files used by initializing an object of that component and calling the methods off the object. However, it seems to me somewhat more straightforward to use the cfinvoke method, especially when only using one method from the component file. What are the differences between these 2 methods of calling a component function and what are the pros/cons of each? When should I use which?
One other benefit of using createObject() is that you can chain the init() method, e.g.
<cfset myObject = createObject("com.path.MyObject").init() />
And if your init() returns this you can go further and chain the method if you don't need to use the object again:
<cfset functionResults = createObject("com.path.MyObject").init().myFunction() />
It's worth pointing out that in CF 9 you can use the new (ahem) new syntax to create objects. For example to create the same object as above and call it's init() I can write:
<cfset myObject = new com.path.MyObject() />
It's neat and I like the option to do this. CF is moving in the right direction in my opinion with features like this.
cfinvoke can only be used in tags.
createObject can be used in both tags & cfscript and tends to be a bit slimmer / easier to read IMO.
Until recently I avoided using cfinvoke because I found it "bulky" but a pro of it is you can dynamically loop over the methods within a CFC. In createobject you can't.
So if for example I've got a CFC which has the methods - method1, method2, method3, method4. I can loop over them like so:-
<cfloop from="1" to="4" index="element">
<cfif structKeyExists(this,'getMethod#element#')>
<cfinvoke component="#this#" method="getLine#local.element#" returnVariable="methodValue"></cfinvoke>
<cfset arrayAppend(myArray,methodValue) />
</cfif>
--
Another thing to note is that some sharing hosts lock down on createobject. Mainly because of the access it gives to the underlining Java.
You've nearly answered it yourself: on the surface, one could say that if you will be calling only one method on a page, then doing in one fell swoop in CFINVOKE (which instantiates the CFC and calls the one named method) make sense. And certainly if you would call more than one method of the CFC on a page, then separating the steps makes sense (instantiate the CFC with the createobject function or cfobject tag, then invoke methods as found in that object, a pointer to the CFC), so that you don't pay that instantiation cost more than once.
But do keep in mind that if the page is called often, it may make sense also to save that result of instantiating the CFC, so that it can be reused on a subsequent request to the page. You would do that by storing it (the result of cfobject/createobject) not in a local variable but instead in a shared scope: whether server, application, or session, based on "who" would benefit from such reuse. Of course, it's then incumbent on you to programmatically handle/decide how long to save this "cached" CFC instance.
As important, when you save a CFC instance this way, you become more susceptible to the "var scope bug", which basically is that you need to be still more careful to VAR any local variables you create in the CFC. Rather than try to elaborate more on that, I'll point out a meta-resource I created on that:
http://www.carehart.org/blog/client/index.cfm/2010/3/4/resources_on_the_var_scope_problem
Hope that helps.
Rather then rehash this discussion I'll just point you towards Google:
http://www.google.com/search?q=cfinvoke+vs+createobject
There are some subtle differences (IE: <cfinvoke> is capable of handling dynamic method names) but essentially it just boils down to personal preference. Well, that and the fact that you can't use <cfinvoke>via <cfscript>.