Why was IsDefined() deprecated? (and less performant alternatives not?)

Though IsDefined() has been a frequent topic recently, I’m fairly certain the following questions and issues deserve their own separate and definitive topic. I have spent literally DAYS researching :face_with_monocle: and obsessing :crazy_face: over every little detail and now away we go!

  1. Why was IsDefined() deprecated? If performance was the only reason, then where should we draw the line between performance vs natural language readability and fewer characters to type for rapid app development? Even with autocomplete, “isD” is fewer characters than “StructK”. Taking the performance argument to the extreme, should Lucee itself be deprecated and replaced with Assembly Language? :stuck_out_tongue_closed_eyes:

  2. As Mark Kruger wrote way back in 2009, “This function is commonly used in most ColdFusion applications. In fact, I would put it in the top 10 of functions used (perhaps the top 5)”. Judging from the frequency of surprised responses within this forum about it being deprecated, its popularity probably hasn’t declined much. It is also apparently not deprecated in Adobe CF, which will make cross-platform compatibility more difficult should IsDefined() ever be completely removed from Lucee in the future. That doesn’t impact me personally since I migrated from Adobe CF to Lucee about 5 years ago and never looked back, but it’s something to consider when encouraging Adobe CF managers and devs to make the switch.

  3. Other than StructKeyExists(), the other alternatives ParameterExists(), !isNull(), and the Elvis null-coalescing operator all appear to be even less performant than IsDefined(). If performance is the sole criteria, then why haven’t those also been deprecated? Note: ParameterExists() is deprecated in Adobe CF. Maybe the Lucee doc page just need to be updated?

  4. What if traversing all the scopes is precisely the functionality that’s needed for a specific case? And since IsDefined() has the best performance in that case, do we now have a reason for IsDefined() to be … umm … undeprecated? Or is the act of deprecating it a means of encouraging developers to learn about the performance impact? If so, that doc page needs that explanation and recommendations for replacements, and also … return to #3. :point_up_2:

  5. Is it feasible to change the Java algorithm for IsDefined() to limit the scope when specified instead of traversing all scopes so its performance is on par with StructKeyExists()? And while we’re at it, can we remove the requirement for the argument to be a string so it’s more like ParameterExists() and IsNull()? :smiley: Seriously though, that would be less keystrokes not having to type the double quotes.

  6. OR … improve the performance of IsNull()? Semantically, though, I prefer IsDefined() because a var can be defined as NullValue() and though that is treated as if it doesn’t exist, in fact the key still exists within its defined scope (see my gist below). OTOH, IsDefined() isn’t 100% semantically correct either, when the var is defined as NullValue(). I know that’s because of how “truthiness” works in Lucee (and Java?), but nevertheless … well now it looks like I’m arguing for IsDefined() and IsNull() to both be deprecated because they’re not 100% semantically correct. HAHA brain fog! :face_in_clouds:

IsNull() Not So Different Than IsDefined()

Ben Nadel: “From what I have seen and heard before, I believe that IsNull() gets converted to StructKeyExists() at compile time;”

Safe Navigation Operator Also?

Adobe CF Language Enhancements: “Generally, a referenced variable is searched in various scopes before a match is found. In cases where a variable is not found in common scopes like function, local scope, and variable scopes, the search continues in implicit scopes, which can take a while.”

Is that different in Lucee? Because in my benchmarks SNO is 2nd fastest after StructKeyExists().

BENCHMARKS

First it’s important to verify that the compared function and operator results are equivalent, so let’s start with this:

WhatIsTruth('Url.foo not declared');
Url.foo;
WhatIsTruth('Url.foo;');
Url.foo = NullValue();
WhatIsTruth('Url.foo = NullValue();');
Url.foo = "hey";
WhatIsTruth('Url.foo = "hey";');

function WhatIsTruth(header) {
	echo('<h1>#header#</h1>');
	dump(label='Url', var=Url)
	dump(label='IsDefined("Url.foo")', var=IsDefined("Url.foo"));
	dump(label='ParameterExists(Url.foo)', var=ParameterExists(Url.foo));
	dump(label='StructKeyExists(Url, "foo")', var=StructKeyExists(Url, "foo"));
	dump(label='!isNull(Url.foo)', var=!isNull(Url.foo));
	dump(label='(Url.foo ?: false) != false)', var=(Url.foo ?: false) != false);
	dump(label='(Url.foo ?: false) !== false)', var=(Url.foo ?: false) !== false);
	dump(label='Url?.foo != NullValue()', var=Url?.foo != NullValue());
	dump(label='Url?.foo !== NullValue()', var=Url?.foo !== NullValue());
	echo("<br>");
}

The only difference is != vs !== for safe navigation, though I like that differentiation for the case of Url.foo; because an empty string is not equal to NullValue().

The timers I forked from @Zackster and bumped the iterations up to a million each. Though this isn’t a real world benchmark, it’s probably enough evidence since StructKeyExists() consistently shows the best performance … except when I run it on my laptop where (surprisingly?) the safe navigation operator is comparable to or even faster!

echo('IsDefined("Url.customer")');
timer type="outline" {
	loop times=1000000{
		IsDefined("Url.customer");
	}
}
echo('StructKeyExists(Url, "customer")');
timer type="outline" {
	loop times=1000000{
		StructKeyExists(Url, "customer");
	}
}
echo('ParameterExists(Url.customer)');
timer type="outline" {
	loop times=1000000{
		ParameterExists(Url.customer);
	}
}
echo('!IsNull(url.customer)');
timer type="outline" {
	loop times=1000000{
		!isNull(url.customer);
	}
}
echo('Url.customer ?: false');
timer type="outline" {
	loop times=1000000{
		Url.customer ?: false;
	}
}
echo('(Url.customer ?: false) != false');
timer type="outline" {
	loop times=1000000{
		(Url.customer ?: false) != false;
	}
}
echo('(Url.customer ?: false) !== false');
timer type="outline" {
	loop times=1000000{
		(Url.customer ?: false) !== false;
	}
}
echo('Url?.customer !== NullValue()');
timer type="outline" {
	loop times=1000000{
		Url?.customer !== NullValue();
	}
}
2 Likes

How would you go about checking whether, for example, the form scope or url scope exists without using isDefined - before then being able to check specific entities in that scope with structKeyExists?

1 Like

please see Deprecated Tags & Functions :: Lucee Documentation

Thanks, but that just notes that isDefined is depreciated but doesn’t offer a “[…] newer, more modern way(s) to achieve the same result.”

2 Likes

Thank you for confirming that IsDefined() is deprecated and its less performant alternatives are not, but I was hoping for actual answers to my questions, in depth group discussion, and maybe some kind of judgment by committee. :slightly_smiling_face:

alas, you’re more than several years late to the party, check the archives!

I did check the archives, rather thoroughly in fact, which is precisely why I posted this topic. So there’s no room for rethinking it?

Also in the archives I saw no discussion for why its less performant alternatives are also not deprecated.

They both always exist and are empty by default.

There may be other scopes that are worthy of checking their existence? Either way, what about my six issues?

1 Like

Maybe I misunderstood. Are you referring to the old Google Groups or something else other than this Lucee Dev Forum? Have all six of my issues been discussed before? My questions aren’t rhetorical nor is it my intention to be a rabble-rouser. I put some serious logic into all of this and I’d appreciate thoughtful responses point by point instead of dismissing it all outright. Just because it was decided two years ago, doesn’t necessarily mean it was the right decision if all the issues I’ve raised were not included in that discussion, nor is it documented here for others who have the same thoughts.

yes, see the forum archives here.

“performant”? this is all splitting hairs over perhaps a millisecond, the function was deprecated due to limitations in the function which makes it unreliable, which cannot be changed due to backwards compatibility with cfml

the function isn’t being removed, it’s just not recommended anymore

Yep, bad example, but you know what I mean.

That was 13 years ago? I’d ask myself how does it look today, specifically in most modern cfml applications? I doubt it is in the top 5 or top 10.

I need to use isdefined() only once when I have an application that dynamically activates session managment, but only because the session scope doesn’t exist when session managment is deactivated.

@Zackster, as I said twice already, I did see the forum archives here. I spent DAYS looking for answers, and my questions were in fact NOT answered here.

Finally the answer to my question. Thank you!

The reason why I thought performance was the sole reason is because that was your response to @Simon_Goldschmidt when he inquired about it last month:

At that time you did not mention anything about it being unreliable, nor was that previously stated by anyone else anywhere within this forum.

@andreas I doubt that, too, but what I actually said was: “Judging from the frequency of surprised responses within this forum about it being deprecated, its popularity probably hasn’t declined much.”

At the very least, the fact that people are still asking about it shows that people are still using it, which indicates the need for better communication about it being deprecated.

They both always exist and are empty by default.

… for what it’s worth, when Adobe ColdFusion is invoked as a WebService (?wsdl), the form scope is not defined. At least. this is how it worked a million years ago - not sure if htis is still the case today. I haven’t tried using a WebSerivce in at least a decade.

That said, using isDefined() was the only way I could figure out (at the time) how to check to see if ACF form scope existed. Of course, like I said, I basically never use WebServices. Not sure how Lucee even handles them since I have not had the need to test.

1 Like

As @ASKemp pointed out earlier, there should at least be some description and alternatives added to IsDefined() :: Lucee Documentation and the list of deprecations.

Sebastian

1 Like

Well, seeing how the last book on ColdFusion was written in the stoneage, maybe a modern guide would be in order.

1 Like

I use the following:
form.keyExist(“the_variable”)
url.keyExists(“the_variable”)

That format restricts the search to the scope you’ve indicated.

1 Like

Cool … cool … so how long will it be fully supported? Asking for my future self. :grimacing:

I’ve been watching this slow burning thread and decided I should see how many uses of it I have.

  • Searching “isDefined” (not case-sensitive) found 680 hits in ~200 files (~7% of my cf* files) :astonished:

The larger issue in converting will be the frameworks and other tools (WAF) where we don’t want to introduce an unintended bug and will need to make sure the updated code performs EXACTLY as intended.
Some uses were intentionally written in a way to check if a “password” (PII variable) was passed from ANY scope, handle it a certain way: (clear it, do not accept it, overwrite it when done, and/or sanitize logged output).

YMMV but it’s a handy (maybe overused) function IMHO. :sweat_smile:

1 Like