Wednesday, 27 August 2014

What would you do?

G'day:
Here's a quick one.

If you had a requirement to have a function which returned two things: a result, and optionally some telemetry on the process being run; and there were two distinct bits of data, and the nature of the requirement is such that the telemetry cannot pollute the return variable. How might you do that?

Here's two options (and they're not the only two options, that's beside the point here):

public Thing function getTheThing(required string typeOfThing, string telemetryVariableName){
    variables[telemetryVariableName] = {status="OK", something="else"};
    return new Thing(typeOfThing);
}

thing = getTheThing("badger", "variableForTelemetry");
writeDump([thing, variableForTelemetry]);

We have an argument which provides the name of a variable to set, and the code busts out into the calling context and sets that variable. This leaves the return value to just return the thing the function actually needs to return.

Alternatively we could do this:

public Thing function getTheOtherThing(required string typeOfThing, struct telemetry){
    structAppend(telemetry, {status="OK", something="else"});
    return new Thing(typeOfThing);
}

telemetryVariable = {};
otherThing = getTheOtherThing("parsnip", telemetryVariable);
writeDump([otherThing,telemetryVariable]);

We actually pass-in the variable to have the telemetry data to be put into. Now because CFML is not truly pass-by-reference, we have to append the data to that, but that's OK.

There'd be other ways.

Given those two options, the first option seems very jerry-built to me. Passing in the name of a variable, instead of the actual variable? Bleah. It just seems more natural to me to do the latter.

That's where I came undone today using queryExecute(). I tried this:

result    = {};
numbers = queryExecute("
    SELECT    id, en, mi
    FROM    numbers
    WHERE    id BETWEEN ? AND ?
",
[1,4],
{
    datasource    = "scratch_mysql",
    result        = result
});

I just assumed the result value - this is the one that contains the columns, SQL statement, etc of the resultant recordset - would be a struct I'd give it. But no. I just get this:

Error Occurred While Processing Request
Error casting an object of type coldfusion.runtime.Struct cannot be cast to java.lang.String to an incompatible type. This usually indicates a programming error in Java, although it could also mean you have tried to use a foreign object in a different way than it was designed.

coldfusion.runtime.Struct cannot be cast to java.lang.String


Huh? Then I sigh. And change the code to be this:

{
    datasource="scratch_mysql",
    result        = "result"
}

It takes the bloody name of the variable.

That seems really leaden to me. How would you have done it?

--
Adam