1

I really hope you can help me. I usually read my session variables into a local variable, so that I don't have to create endless read locks. But I came across some interesting behavior. Note that I have not applied any write locks for brevity's sake:

Consider the following:


EXAMPLE 1:

<cfset session.testvalue = 1 /> <cfset lcktestvalue = session.testvalue /> <cfoutput>#lcktestvalue#</cfoutput><br /> <cfset session.testvalue = 2 /> <cfoutput>#lcktestvalue#</cfoutput> 

OUTPUT:

1
1


EXAMPLE 2:

<cfset session.testvalue1.item = 1 /> <cfset lcktestvalue1 = session.testvalue1 /> <cfoutput>#lcktestvalue1.item#</cfoutput><br /> <cfset session.testvalue1.item = 2 /> <cfoutput>#lcktestvalue1.item#</cfoutput> 

OUTPUT:

1
2


I am trying to work out why the second example, updates the 'lcktestvalue1.item', when the value was only read once? I would have expected example 1 & 2 to produce the same output, and the following to produce the second example's output:


EXAMPLE 3:

<cfset session.testvalue1.item = 1 /> <cfset lcktestvalue1 = session.testvalue1 /> <cfoutput>#lcktestvalue1.item#</cfoutput><br /> <cfset session.testvalue1.item = 2 /> <cfset lcktestvalue1 = session.testvalue1 /> <cfoutput>#lcktestvalue1.item#</cfoutput> 

OUTPUT:

1
2


The only reason for this behavior, I can think of, is that the second example, uses a structure inside a structure. But,I cannot expand on this concept. Can you? I really need to understand this, because I am creating a shopping cart, which makes extensive use of the methodology in example 2. It actually works fine, but I am not sure why, and I am afraid under load, it may fail?

Thank you for any help you can give me on this.

2
  • "Endless read locks"? What version of CF are you using? Unless you're dealing with some funky race conditions you probably don't need to lock session variables at all. Commented Nov 19, 2014 at 16:55
  • Better to be safe than sorry. I have heard quite a few scare stories about session race condition, even with CF10. From what I have read, there are a couple of bugs, which means that this issue still has not been fully addressed by Adobe. Commented Nov 19, 2014 at 17:33

3 Answers 3

9

Because your second example is making a pointer, or a reference, from the original value to the new value. You can think of it is an imaginary string between the two such that when one is changed - the other is as well. This happens with structures. You can get around this by using duplicate.

But NOTE! The need to obsessively cflock session/app/server variables has NOT been necessary for nearly ten years. You still have to worry about race conditions, but for 99% of the time this is not your concern.

Sign up to request clarification or add additional context in comments.

1 Comment

Ray. Thanks for this very concise & visually appealing answer. I like the string idea. I used to read session values into a local variable, so that I could avoid numerous read locks, but I guess old habits die hard!
6

Charles, This is is expected behavior. Structures and objects are passed by reference - meaning you are actually just setting a pointer to a memory location to get at the underlying object. When the set statement is dealing with a primitive (a string, number, date etc) it copies the data into your new variable - so this:

<Cfset session.testvalue = 1/> <cfset testvalue = session.testvalue/> 

...actually creates 2 locations each containing a "1"

When you are dealing with an object however (a structure, component, function, query etc. - anything not primitive), like this:

<cfset session.testvalue.item1 = 1/> <cfset testvalue = session.testvalue/> 

The variables.testvalue variable is actually a pointer to the structure you created in the set statement (session.testvalue.item1 implicitely creates a structure).

This is important fundamental stuff - especially when dealing with CFCs, functions, application scopes etc. This post on Primitive vs complex variables explains it in more detail.

It has nothing to do with locking by the way. Unless you have some demonstratable race condition you need not go overbord with locking.

I would note that your practice here is probably not a great idea - you should probably be scoping your local vars as variables.varName any way in which case pushing session variables to that scope is not saving you any effort.

NOTE: While I was writing this Ray chimed in with a short concise answer exactly to the point (while I was being verbose).

NOTE 2: In ColdFusion there is one nuance that some find unexpected - arrays are passed by value (as a copy) and not by reference. This can throw you sometimes - and if you ever do an array of objects

7 Comments

Sorry Ray, I made sure and noted that you were first to answer this.
Thanks Mark. Great explanation. Can I infer that my SESSION values are still safe. Presumably the pointer has a hidden sessionid, as well, which differentiates between many different users' sessions?
Not sure what you are asking - but if you mean safe as in tied to the user then us. There is a sessionID (which can take a couple of forms in CF) that is tied to a cookie. In your specific example you can screw up data per user but not accross users. For that you would need to use the same approach with Application variables :D
Just one little question. Are you sure I need to prefix local variables, when there are just local & session scopes being used in a CF template. I understand, that this is good practice when there are 'url' & 'form' variables flying around. Although, in certain cases, it is advantageous not to differentiate between 'local', 'form' & 'url', if you want to implement a first come, first read system.
"In your specific example you can screw up data per user but not accross users". How would it be possible to screw up data per user? Sorry, I am not clear on this?
|
0

You should use Duplicate() if you want to copy/clone the structure and not just make a reference to the object stored in SESSION.

 <cfset session.testvalue1.item = 1 /> <cfset lcktestvalue1 = Duplicate(session.testvalue1) /> <cfoutput>#lcktestvalue1.item#</cfoutput><br /> <cfset session.testvalue1.item = 2 /> <cfoutput>#lcktestvalue1.item#</cfoutput> 

Output

 1 1 

Coldfusion WikiDocs

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.