Skip to main content
Ben Nadel at CFUNITED 2008 (Washington, D.C.) with: Yaron Kohn
Ben Nadel at CFUNITED 2008 (Washington, D.C.) with: Yaron Kohn

Function Hoisting In ColdFusion

By on
Tags:

The other day, in the comments to my post on using a ColdFusion custom tag to define a ColdFusion component, I mentioned that my solution was slightly flawed - that it didn't take into account the underlying function hoisting that was going on. I don't think I've ever talked about function hoisting before, so I thought I would write a quick post about it. In my mind, function hoisting is a "side effect" of parsing and it is not necessarily something that should be considered a "feature" of the language (or any language for that matter).

I don't know what the technical definition of "hoisting" is; but, more or less, it's the implicit movement of function and variable declarations to the top of their defining context. In ColdFusion, we use function declarations all the time. We also use variable declarations, although I think we are much less aware of it; simply setting a variable isn't a declaration - using the "var" keyword denotes a variable declaration.

NOTE: Until CF9, ColdFusion required variable declarations to be at the top of their function context. As such, no real hoisting was necessary.

So, what does function hoisting mean for our code? It means that we can reference a function even if it is defined after the line of code that references it:

<!--- Use the function defined at the bottom of the page. --->
<cfoutput>
	#sayHello()#
</cfoutput>


<!--- Define our say hello function. --->
<cffunction
	name="sayHello"
	access="public"
	returntype="string"
	output="false"
	hint="I return a hello statement.">

	<cfreturn "Hello my lady; you look beautiful today." />
</cffunction>

When we run this code, we get the following output:

Hello my lady; you look beautiful today.

As you can see, even though the function, sayHello(), is defined at the bottom of the page, the code at the top of the page can still make use of it. This is because the function is being "hoisted" to the top of the defining context (the page in this case).

Again, I am not recommending that you do this. Just as with the use of CFHTMLHead, writing code that cannot be understood clearly in a top-down manner is never something that I'll recommended. I'm just demonstrating this because it's a feature of which people should be aware.

Now, I am a little bit of a hypocrite. One place that I do personally leverage this feature is in the pseudo constructor of a ColdFusion component. I will, at times, invoke a component method from within the pseudo constructor of the same component. This works because, although my calling code is at the top of the component, all of the declared functions are implicitly hoisted to the top of that context.

Of course, I am sure there are a number of people who frown upon the concept of a pseudo constructor in general. So, perhaps this is just one bad behavior making use of another.

One side effect of function hoisting is the fact that functions cannot be declared conditionally. That is, I can't use external logic to define my CFFunction tags:

<!--- Check to see which kind of function we should define. --->
<cfif (true || userHasStreetCred())>


	<!--- Define one version of the function. --->
	<cffunction
		name="getAccess"
		access="public"
		returntype="string"
		output="false"
		hint="I return access permissions.">

		<cfreturn "public,console,shop,admin,settings" />
	</cffunction>


<cfelse>


	<!--- Define another version of the function. --->
	<cffunction
		name="getAccess"
		access="public"
		returntype="string"
		output="false"
		hint="I return access permissions.">

		<cfreturn "public,settings" />
	</cffunction>


</cfif>

As you can see, I am trying to use a conditional statement in order to help define my functions. I know this is a silly example; but, when we run this code, we get the following ColdFusion error:

Routines cannot be declared more than once. The routine getAccess has been declared twice in the same file.

The reason we get this error is because the two function declarations are being hoisted to the top of the context where they are no longer in a conditional setting. As such, ColdFusion sees them both as being declared which is, as you probably know, not allowed.

Going back to my ColdFusion custom tag post, the error that I made in judgement was thinking that CFFunctions defined within a custom tag body would be defined after the Start Mode of the custom tag had executed. Of course, once you understand hoisting, you quickly realize that this is not the case.

Function hoisting (and variable hoisting) is not ColdFusion specific; this also happens in Javascript as well and I would be surprised if other languages didn't have similar concepts. Function hoisting is definitely a feature of the language that you should be aware of; but, I wouldn't say that it is a feature you should necessarily try to leverage.

Want to use code from this post? Check out the license.

Reader Comments

1 Comments

Function hoisting sounds like the use of the "GOTO" statement in other languages, something that is usually frowned at because of its ugliness.

198 Comments

RE: Conditional defining of functions, that's one area that closures can help. For example, in JavaScript you *can* do:

if( hasStreetCred() ){
var getAccess = (function (){
return function (){
return "public,console,shop,admin,settings";
}
})();
} else {
var getAccess = (function (){
return function (){
return "public,settings";
}
})();
}

Obviously, the above example isn't a good use case, but it can be useful if you want to define a something that's optimized by browser. For example, the logic to do something efficiently in IE might be different than in other browsers, so this technique can be helpful in those cases.

3 Comments

"NOTE: Until CF9, ColdFusion required variable declarations to be at the top of their function context."

I did not know that (and wish that I had known that before now)!!!

Thanks for that little nugget Ben... it was a CF "feature" that had been bugging me for a long time.

2 Comments

OK - sorry for the repeats but IE and FF say and unknown error occurred whilst scrolling to the bottom of the page hence I thought they hadn't posted (food for thought in clever scrolling).

54 Comments

You said function hoisting and I got really surprised. JavaScript has function hoisting, what you are showing I wouldn't really consider hoisting. It's more like 'declarations happen before anything else. JS has hoisting but you can reference variables like this.

var hello virtually happens with hoisting
alert hello alert box undefined
var hello - hi!

That's hoisting.

Unknown error is killing my comment

15,640 Comments

@Dan,

Yeah, being able to use functions in expressions gets around the hoisting. Perhaps one day, we'll have function expressions in ColdFusion :)

@Nigel,

Yeah, I believe that a CFInclude would work since the include isn't actually executed unless the conditional is run.

@Drew,

I am not sure I follow what you are saying. I am saying that hoisting is the movement of declarations to the top. Can you clarify what you mean?

@Nigel, @Drew,

Sorry about the repeats; apparently my mail server died and the UNDLVR folder actually killed the space on my server HD. Should be good now (fingers crossed).

1 Comments

You could assign functions to a variable?

---
<cfset theFunction = aFunction />

<cfset theFunction() />

<cfset theFunction = bFunction />

<cfset theFunction() />

<cffunction name="aFunction">
A function.
</cffunction>

<cffunction name="bFunction">
B function.
</cffunction>
---

Output: A function. B function.

Or did I misunderstood?

3 Comments

I think I would call "Hoisting" something more like the order of CF compilation. AFAIK it goes something like this:

1) compile cf page (basic error checking, look for bad operators, unclosed cftags, etc.) into its own java class file
2) compile functions individually (into separate java classes)
3) run through CF page procedurally

It makes sense to me, but it is unfortunate that you can't create cffunctions conditionally. The solutions are obvious (to me), either what Dominique suggested of defining both functions and then making a pointer to either one or the other, or probably the cleaner way would be to do it with object composition, where you have a family of objects with the same method name.and depending on which object is given or needed, you still call the same method name. I'm just saying, it's something that can be easily overcome.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel