Earlier today Tony Nelson pinged me about an odd ColdFusion issue he ran into. It turned out to be an issue I've seen before outside of CFCs that - for whatever reason - acted somewhat different inside of a CFC. Let me explain a bit. First, let's look at his CFC.
function init(string foo, string bar, string baz) {
_set(foo, bar, baz); } function _set(string foo, string bar, string baz) { } }
component {
Nothing crazy here, just an init method that automatically calls a method called _set that takes three arguments. Each argument is optional (don't forget about that chnage) so any amount of strings sent in should be fine. Now let's look at calling code:
<cfset z = new test("foo", "bar", "baz")>
When executed, you get:
Parameter validation error for the _SET function.
The function accepts 2 to 2 parameters.
Eh? I decided to simplify things a bit to see if it would help. I changed it to one CFM that looked like so:
<cfoutput>#_set()#</cfoutput>
<cffunction name="_set">
<cfreturn 1>
</cffunction>
Whenever I debug I try to simplify as much as possible. When run, I got:
The names of user-defined functions cannot be the same as built-in ColdFusion functions.
The name _set is the name of a built-in ColdFusion function.
Ahah! So I've seen this before in terms of UDFs with the same name as BIFs, but _set isn't a ColdFusion function, is it? Turns out it is - just behind the scenes. Turns out if you look at the Java object coldfusion.runtime.CfJspPage, you see this method defined:
<cfset foo = createObject("java","coldfusion.runtime.CfJspPage")>
<cfdump var="#foo#">
I tried making UDFs with names from a few of the methods defined here and they all threw errors. For the most part I avoid weird names like _set so this wouldn't trip me up, but some of the methods did look like something I'd consider using like release(). It appears as if when executing as a CFM only, ColdFusion was better able to handle the error. But when executed via a CFC method the error is more ambiguous. In case you want to see a full list of the methods and don't want to run the code above, I whipped up this little script:
<cfset foo = createObject("java","coldfusion.runtime.CfJspPage")>
<cfset methods = foo.getClass().getDeclaredMethods()>
<cfset allMethods = []>
<cfloop index="m" array="#methods#">
<cfif not arrayFind(allMethods, m.getName())>
<cfset arrayAppend(allMethods, m.getName())>
</cfif>
</cfloop>
<cfset arraySort(allMethods, "textnocase")>
<cfloop index="m" array="#allMethods#">
<cfoutput>#m#<br/><br/></cfoutput>
</cfloop>
And here's the output:
__caseValue
_addBD
_arrayAssign
_arrayGetAt
_arrayset
_arraySetAt
_autoscalarize
_autoscalarizeWithoutLocalScope
_Binary
_checkCFImport
_checkCondition
_checkParam
_clone
_compare
_contains
_div
_divideBD
_echoExpr
_emptyTag
_emptyTcfTag
_escapeSingleQuotes
_get
_getImplicitMethod
_getImplicitMethods
_idiv
_initTag
_invoke
_invokeUDF
_isDefined
_isNull
_isTopPage
_iteratorCollection
_LhsResolve
_mergeToLocal
_mod
_multiplyBD
_negateBD
_popBody
_powBD
_pushBody
_resolve
_resolveAndAutoscalarize
_set
_setCurrentLineNo
_setImplicitMethods
_setNonLocalScope
_structSetAt
_subtractBD
_templateName
_validateTagAttrConfiguration
_validateTagAttrValue
_validatingMap
_whitespace
ArrayGetAt
bindImportPath
bindPageVariable
bindPageVariables
checkRequestTimeout
checkSimpleParameter
createInitialValue
GetComponentMetaData
getExtends
getImplements
GetMetaData
getOutput
getPagePath
getQueryParamCount
getResolvedComponentPath
initialize
internalIsBoolean
internalIsNumeric
internalIsNumericDate
invoke
isNotMap
registerUDF
registerUDFs
release
resolveCanonicalName
runPage
setResolvedComponentPath
StringCouldBeODBCDateTime
StructStemGet
URLSessionFormat
urlSessionFormat
Finally, it does not as if this is documented. The Live Docs page for reserved words has this to say:
Built-in function names, such as Now or Hash
But there is no warning about possible conflicts with these "hidden" methods. Has anyone else run into this?