Thursday 9 May 2013

A coupla bits of curious behaviour

G'day:
Here's a coupla bits of code that undid me yesterday. What do you make of these code examples:


<cfscript>
    q= queryNew("");
    queryAddColumn(q, "col", "integer", [1,2,3,4,5]);

    array function columnToArray(required array a){
        writeOutput("Inside:<br>");
        writeOutput('isArray(a): #isArray(a)#<br>');
        writeOutput('a.getClass().getName(): #a.getClass().getName()#<br>');

        return arguments.a;
    }
</cfscript>

<cfoutput>
    Outside:<br>
    isArray(q["col"]): #isArray(q["col"])#<br>
    q["col"].getClass().getName(): #q["col"].getClass().getName()#<br>
    <cfset result = columnToArray(a=q["col"])>
</cfoutput>

In this code, I pass a query column reference into a function which expects an array argument. I then pass it straight back out, expecting if it was accepted as an array when inbound to the function, it would still qualify as an array three lines later when I return it. Interestingly: no...

Outside:
isArray(q["col"]): YES q["col"].getClass().getName(): coldfusion.sql.QueryColumn
Inside:
isArray(a): NO
a.getClass().getName(): coldfusion.sql.QueryColumn

The web site you are accessing has experienced an unexpected error.
Please contact the website administrator.

The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request

The value returned from the columnToArray function is not of type array.



Am I missing something here? Is it an array or not? And how does passing it to a function change this?


Next is something I found when trying to work around this glitch. Consider this code:

array function f(required any x){
    try {
        return x;
    }
    catch(any e){
        writeOutput("#e.message# #e.detail#");
        return [];
    }
}

f("");

Here I am trying to return a string when I should be returning an array, and instead of the try/catch intercepting this, I still get an error:

The value returned from the f function is not of type array.

If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible.
The error occurred inD:\websites\www.scribble.local\cf\cfml\statements\return\typeException.cfm: line 12
10 : }
11 : 
12 : f("");
13 : </cfscript>

Now this is not a compile-time consideration, so why does the try/catch not work? Why is the error occurring where the function is called rather than where the erroneous return statement is?

Both seem like bugs to me, but I'm hoping perhaps someone can point out where my expectations are off?

Back to interfaces at lunchtime, and I should have something up this evening. Ths lot is just annoying me now, hence posting about it now. ;-)

UPDATE:
Thanks to Dave's comments below, I simplified the code to check a slightly different approach to the same situation:

<cfset q = queryNew("")>
<cfset queryAddColumn(q, "col", "integer", [1,2,3,4,5])>

<cfoutput>
Query column directly:<br>
isArray(q["col"]): #isArray(q["col"])#<br>
q["col"].getClass().getName(): #q["col"].getClass().getName()#<br>
arrayIsEmpty(q["col"]): #arrayIsEmpty(q["col"])#<br>
<hr>

Query column by reference:<br>
<cfset a = q["col"]>
isArray(a): #isArray(a)#<br>
a.getClass().getName(): #a.getClass().getName()#<br>
arrayIsEmpty(a): #arrayIsEmpty(a)#<br>
</cfoutput>

This yields:

Query column directly:
isArray(q["col"]): YES
q["col"].getClass().getName(): coldfusion.sql.QueryColumn
arrayIsEmpty(q["col"]): NO

Query column by reference:
isArray(a): NO
a.getClass().getName(): coldfusion.sql.QueryColumn
arrayIsEmpty(a): 


Object of type class java.lang.String cannot be used as an array


The error occurred inD:\websites\www.scribble.local\cf\datatypes\query\columnType.cfm: line 15
13 : isArray(a): #isArray(a)#<br>
14 : a.getClass().getName(): #a.getClass().getName()#<br>
15 : arrayIsEmpty(a): #arrayIsEmpty(a)#<br>
16 : </cfoutput>

I do know what's going on here... it's this thing that depending on context, CF will either see a column reference as [the whole column, so equitable with an array] or [the value in the first row of the column, so a string], but I think CF is getting the context messed up here. isArray() should be seeing a as an array if it's quite happy to describe it as a coldfusion.sqlQueryColumn still. As per my comment to Dave: CF can't have it both ways.


--
Adam