Wednesday, 16 April 2014

Odd behaviour with struct keys with dots in their names

G'day:
I've been looking at this one due to an interesting question on Stack Overflow: "Confusion in dynamic variable access in ColdFusion". I could not immediately see what the problem was, and it's taken me a coupla hours to work out what's going on.

Here's some code that demonstrates the issue at hand:

key1 = "prefix.key1";
key2 = "prefix.key2";

st = {};
"st.#key1#" = "set via quoted variable name";
st[key2] = "set via associative array notation";
writeDump(st);

writeDump(var=[
    {key1=isDefined("st.prefix.key1")},
    {key2=isDefined("st.prefix.key2")}
], label="isDefined()");
writeDump(var=[
    {prefix=structKeyExists(st, "prefix")},
    {"prefix.key1"=structKeyExists(st, "prefix") && structKeyExists(st.prefix, "key1")},
    {key1=structKeyExists(st, "prefix.key1")},
    {key2=structKeyExists(st, "prefix.key2")}
], label="structKeyExists()");

safe(function(){
    writeOutput("st.prefix.key1: #st.prefix.key1#<br>");
});

safe(function(){
    writeOutput("st.prefix.key2: #st.prefix.key2#<br>");
});

safe(function(){
    writeOutput("st['prefix.key2']: #st['prefix.key2']#<br>");
});

function safe(f){
    try {
        f();
    }catch (any e){
        writeOutput("#e.type# #e.message# #e.detail#<br>");    
    }
}

Here we set to values in a struct: one using erm... dunno what the syntax is call, but the syntax of using a quoted dynamic value as a dynamic variable name; and the other using associative array notation.

Then we output various odds 'n' sods like whether the variable is defined, whether various keys exist, and then the variables' values.

The safe() function is just there to de-clutter the code somewhat.

And this is the output...

ColdFusion 10 (and lower):

struct
prefix
struct
key1set via quoted variable name
prefix.key2undefined
isDefined() - array
1
isDefined() - struct
KEY1YES
2
isDefined() - struct
KEY2NO
structKeyExists() - array
1
structKeyExists() - struct
PREFIXYES
2
structKeyExists() - struct
prefix.key1YES
3
structKeyExists() - struct
KEY1NO
4
structKeyExists() - struct
KEY2YES
st.prefix.key1: set via quoted variable name
Expression Element PREFIX.KEY2 is undefined in ST.
st['prefix.key2']: set via associative array notation


See how the dump can't see the value of the prefix.key2 key, nor can isDefined(), and nor can actually outputting it using dot notation.

But the value is actually there.

ColdFusion 11 is much the same, except for the dump working properly:

struct
prefix
struct
key1set via quoted variable name
prefix.key2set via associative array notation

And Railo works the same as ColdFusion 11.

Interestingly, if I comment-out this:

"st.#key1#" = "set via quoted variable name";

Then prefix.key2 is completely visible across the board.

The thing is that once there's a substruct called prefix created, ColdFusion / Railo gets confused when trying to access prefix.key2. They decide that it's not a key name, but a reference to a subkey key2 within the prefix substruct. Which - of course - does not exist.

I can see how this happens, but it possibly shouldn't? What do you think?

--
Adam