Duncan's blog

March 12, 2009

The importance of var scoping

Filed under: Coldfusion — duncan @ 9:33 pm
Tags: , , ,

As I mentioned in my Introduction to ColdFusion Components, var scoping is essential. This applies not just to CFCs, but to any functions in your CFML.

Let’s illustrate why…

Just for fun, I’m constructing an array with some ‘interesting’ entries from the menu of Heston Blumenthal’s Fat Duck restaurant*. Then I have a function that works out some random scores for each item.

<cfset food = ArrayNew(1)>

<cfset food[1] = "nitro-green tea and lime mousse">
<cfset food[2] = "snail porridge">
<cfset food[3] = "roast foie gras ""benzaldehyde""">
<cfset food[4] = "salmon poached in liquorice gel">
<cfset food[5] = "nitro-scrambled egg and bacon ice cream">

<cfloop index="i" from="1" to="#ArrayLen(food)#">
	<cfset rating = getRating(i)>
	
	<cfoutput>
		#i#. #food[i]#: #rating#<br>
	</cfoutput>
</cfloop>


<cffunction name="getRating">
	<cfargument name="rating" required="yes" type="numeric">
	
	<cfset score = 0>
	
	<cfloop index="i" from="1" to="3">
		<cfset score = score + RandRange(1,10)>
	</cfloop>
	
	<cfreturn score>
</cffunction>

What I expect to see is something like:
1. nitro-green tea and lime mousse: 17
2. snail porridge: 9
3. roast foie gras “benzaldehyde”: 22
4. salmon poached in liquorice gel: 11
5. nitro-scrambled egg and bacon ice cream: 20

Instead what I get is:
4. salmon poached in liquorice gel: 14
4. salmon poached in liquorice gel: 12
4. salmon poached in liquorice gel: 24
4. salmon poached in liquorice gel: 9
4. salmon poached in liquorice gel: 21

So, what’s going on? Well, the problem comes from the simple fact that I’ve failed to var scope the loop counter i in my function. Each time the function getRating is called, i ends up being equal to 4 at the end. You might expect it to end up being equal to 3. However, the way the loop works is that we add 1 to it until it is greater than the to attribute. Once it equals 4 we can stop looping.

So after we call getRating, when I refer to i in my code to reference a value in my array, I will always get the 4th array element.

What if I change the function to give me more random scores; let’s say I want to increase from 3 to 10:

<cffunction name="getRating">
	<cfargument name="rating" required="yes" type="numeric">
	
	<cfset score = 0>
	
	<cfloop index="i" from="1" to="10">
		<cfset score = score + RandRange(1,10)>
	</cfloop>
	
	<cfreturn score>
</cffunction>

This will throw an error due to i now being larger than the size of our array:

The element at position 11 of dimension 1, of array variable "FOOD," cannot be found. 

How to fix this? Just add in a line in the function, immediately after any tags, but before any other CFML, like so:

<cffunction name="getRating">
	<cfargument name="rating" required="yes" type="numeric">
	
	<cfset var i = 0>
	<cfset var score = 0>
	
	<cfloop index="i" from="1" to="10">
		<cfset score = score + RandRange(1,10)>
	</cfloop>
	
	<cfreturn score>
</cffunction>

Notice that I’ve also changed the initialisation of the score variable, to also be var-scoped. Even though I know that I haven’t used another variable called score elsewhere in my code, this is just as important. Ideally your CFC functions should be de-coupled, i.e. you can’t guarantee that there won’t be external variables that share the same name. So protect everything by var scoping all variables.

This can also apply even when you’re not referring to variables of the same name elsewhere. If two users simultaneously called a page that had a function that wasn’t var scoped, strange things can happen! This is often the cause of mysterious errors that you can’t replicate yourself.

In all cases, the Var Scoper tool is very useful for finding un-var scoped variables.


* The Fat Duck is reputedly the best restaurant in Britain, and one of the best in the world. It has three Michelin stars; there are only two other 3-starred British restaurants. Coincidentally, one of them is located just round the corner from the ‘Duck.

Despite being so highly-regarded, the Fat Duck has just re-opened after a mysterious bout of illness amongst its diners.

Also, for a restaurant that charges £98 for the à la carte menu and £130 for the tasting menu, they’ve got a terrible website!

Advertisements

1 Comment »

  1. […] duncancumming @ 12:02 am Tags: cfcs, cfml, Coldfusion, var scoping As a follow-up to my previous article on var scoping, I wanted to give another […]

    Pingback by The importance of var scoping - part 2 « Duncan’s blog — March 16, 2009 @ 12:03 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: