Duncan's blog

March 16, 2009

The importance of var scoping – part 2

Filed under: Coldfusion — duncan @ 12:02 am
Tags: , , , ,

As a follow-up to my previous article on var scoping, I wanted to give another example.

Someone once mentioned to me that he knew you had to var scope, but he didn’t think it applied to queries. Here’s an example to disprove that.

I’m using the same information as before (a selection of actual dishes from the Fat Duck’s tasting menu), but this time instead of storing the data in an array, I’m using a query. I then loop through the query, and call a function at each iteration, to find out the scores given to each meal by Alice, Bob and Eve.

<cfset getData = QueryNew("ID,Name")>
<cfset QueryAddRow(getData, 5)>

<cfset QuerySetCell(getData, "ID", 1, 1)>
<cfset QuerySetCell(getData, "Name", "nitro-green tea and lime mousse", 1)>

<cfset QuerySetCell(getData, "ID", 2, 2)>
<cfset QuerySetCell(getData, "Name", "snail porridge", 2)>

<cfset QuerySetCell(getData, "ID", 3, 3)>
<cfset QuerySetCell(getData, "Name", "roast foie gras ""benzaldehyde""", 3)>

<cfset QuerySetCell(getData, "ID", 4, 4)>
<cfset QuerySetCell(getData, "Name", "salmon poached in liquorice gel", 4)>

<cfset QuerySetCell(getData, "ID", 5, 5)>
<cfset QuerySetCell(getData, "Name", "nitro-scrambled egg and bacon ice cream", 5)>

<cfoutput query="getData">
	#getData.CurrentRow# of #getData.RecordCount#. #getData.Name#, 

	<cfset rating = getRating(getData.ID)>
	
	#rating#<br>
</cfoutput>


<cffunction name="getRating">
	<cfargument name="rating" required="yes" type="numeric">
	
	<cfset var score = 0>
	
	<cfset getData = QueryNew("ID,Name,Score")>
	<cfset QueryAddRow(getData, 3)>
	
	<cfset QuerySetCell(getData, "ID", 100, 1)>
	<cfset QuerySetCell(getData, "Name", "Alice", 1)>
	<cfset QuerySetCell(getData, "Score", RandRange(1,10), 1)>

	<cfset QuerySetCell(getData, "ID", 200, 2)>
	<cfset QuerySetCell(getData, "Name", "Bob", 2)>
	<cfset QuerySetCell(getData, "Score", RandRange(1,10), 2)>

	<cfset QuerySetCell(getData, "ID", 300, 3)>
	<cfset QuerySetCell(getData, "Name", "Eve", 3)>
	<cfset QuerySetCell(getData, "Score", RandRange(1,10), 3)>
	
	<cfloop query="getData">
		<cfset score = score + getData.Score>
	</cfloop>
	
	<cfreturn score>
</cffunction>

What I expect to see is:
1 of 5. nitro-green tea and lime mousse, 12
2 of 5. snail porridge, 14
3 of 5. roast foie gras “benzaldehyde”, 17
4 of 5. salmon poached in liquorice gel, 15
5 of 5. nitro-scrambled egg and bacon ice cream, 12

What I actually get is:
1 of 5. nitro-green tea and lime mousse, 10
1 of 3. Alice, 19
1 of 3. Alice, 23
1 of 3. Alice, 14
1 of 3. Alice, 11

So what’s going on? The problem comes from the fact that I’ve used a query of the same name in my function as in my .cfm page, and critically, that I haven’t var-scoped it.

So the first time through the loop, my page correctly outputs the record count as 5, and the name of the first dish from the query. Then, as soon as it executes the getRating function, the original query is essentially lost once we say:

<cfset getData = QueryNew("ID,Name,Score")>

Somewhere in ColdFusion’s internal workings it knows it has to loop 5 times. But it no longer retains any memory of what the original query was, and ends up outputting the first row of the new query each time.

All we have to do to fix this is change the above line to:

<cfset var getData = QueryNew("ID,Name,Score")>

This also applies to anything else that can return a query object, such as CFDirectory and CFHTTP.

Incidentally, if the query inside the cffunction didn’t have columns that were referenced in the calling page, an error would be thrown. e.g. if I only did:

<cfset getData = QueryNew("Name,Score")>

then I’d get the following error on the second iteration of the loop:
Element ID is undefined in GETDATA.

Leave a Comment »

No comments yet.

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

Create a free website or blog at WordPress.com.

%d bloggers like this: