Monday 14 July 2014

parameterExists() and stuff like that

G'day:
This is a fairly old school topic. TBH, the mention of parameterExists() was mostly to get your click through, but I do mention it along the way.

Yesterday (note: it's taken me a few days to finish this article... I mean "on July 10") Justin Hall put this out on Twitter:


Discussion ensued (have a look at my timeline from around 7pm BST July 10 if you want to read along. I won't regurgitate it here).

I made the point that isDefined() checks whether a variable with that name exists or not, not an actual variable name. And that if one wanted to do it the way Justin was after then that's what parameterExists() is for (yes, I also reminded him it's been deprecated for a decade).

I also posited that it doesn't make a great deal of sense to have a function one passes a possibly-non-existent variable into to determine whether it exists or not. It's kinda putting the cart before the horse.

But then again parameterExists() does exactly this, so... hmmm. I guess - and Brad offered this - CF is doing some jiggery-pokery (my wording not his) when parsing the code to make it less nonsensical. And that's not really that great.

Actually here's what he said (no need for me to paraphrase):


Justin's right though (that he was right was never contested), PHP does allow this sort of thing:

echo isSet($foo) ? "set" : "not set";
echo "<br>";
  
$foo = "bar";
echo isSet($foo) ? "set" : "not set";

And JavaScript can do this (I'm just keying this into the console):

> typeof foo
"undefined"
> foo = "bar"
"bar"
> typeof foo
"string"

And my own research demonstrates Ruby can do this too:

puts (if defined? foo then "defined" else "not defined" end)

foo = "bar"
puts (if defined? foo then "defined" else "not defined" end)

That's probably a lesson in "how not to write Ruby", but the main thing is the defined? function will happily check a non-existent variable.

And then there's also the isNull() function, as of ColdFusion 9:

writeOutput(isNull(foo));
foo = "bar";    
writeOutput(isNull(foo));

Note isNull() will also work on undefined sub-keys of undefined structs:

writeOutput(isNull(foo.moo));
foo = {};    
writeOutput(isNull(foo.moo));
foo.moo = "bar";    
writeOutput(isNull(foo.moo));

(this outputs "yesyesyno"). I was expecting that to fail, actually.

As of ColdFusion 11 and Railo... 4.1 (?), there's also a null-coalescing operator which also handles undefined values:

foo.moo = foo.moo ?: "default for foo.moo";
writeDump(var=variables, label="after first assignment");

foo.moo = foo.moo ?: "updated default for foo.moo";
writeDump(var=variables, label="after second assignment");

This results in:

after first assignment - struct
FOO
after first assignment - struct
MOOdefault for foo.moo
after second assignment - struct
FOO
after second assignment - struct
MOOdefault for foo.moo

Why am I telling you this? Well there's bunch of better ways to deal with non-existent variables in CFML than using isDefined(), for one thing.

Also I didn't know that isNull() worked on non-existent sub-keys of non-existent structs, so perhaps you didn't either, and this might be handy for you.

And that's it.

--
Adam