As far as I can tell, in boolean context a hash entry that doesn't exist will yield false, as will an entry that's there but undef, as will one that's there but one of the other false values (0, "", "0"). Neither does it seem like referring to a non-existent element will either cause a warning or autovivify anything.

The part that nagged me wasn't that there was an elsif, it was that it said...

if (defined(A) && A) ...

instead of just

if (A)

I think, for a check like this in boolean context, if it is the case that $ENV{SHELLVAR} is not in the hash or in the hash with an undefined value or in the hash with a blank or zero value, it's all the same as far as the condition and "if ($ENV{SHELLVAR})" covers it. My experiments seem to confirm this, but I could be missing something. Perl is pretty complicated when you try to analyze the dwim stuff.

It seems to have been this way since the first version by Chris Kuethe. Good of you to look to the history. I should have done that.

I'm a little wary sending this to misc. I've got this intuition this might be something that's really annoying for me to point out (though apparently not so annoying not to bother you guys with it ... sorry). The last person I want to annoy with novice Perl questions is Marc Espie. Pretty sure there's no practical harm or performance problem to the double check, it just bugs me reading it.

Maybe I could try the local Perl mongers see if they know why someone would write it this way.

Last edited by thirdm; 6th February 2014 at 07:18 PM.
Reason: clarification

As far as I can tell, in boolean context a hash entry that doesn't exist will yield false, as will an entry that's there but undef, as will one that's there but one of the other false values (0, "", "0"). Neither does it seem like referring to a non-existent element will either cause a warning or autovivify anything.

Unfortunately, I don't have as complete an answer as I would like, but I have probably coded similar ambiguities myself, & the following code demonstrates a common issue:

I agree that autovivification shouldn't be the issue (& those interested should review the documentation for defined()...), but I have been burnt by undefined hash elements before (as demonstrated by the example above...) which was alleviated by brute force use of defined().

So to further this hand-waving explanation, I would say that the practice is simply stylistic. Plus, I haven't taken the time to fully grok the CVS history.

A difference between the code you've posted and the pkg-config case is that in your case you only need care if it's undefined before using the hash element. Had you wanted only to print "true" values and written ...

print "'$k'\t'$h{$k}'\n" if defined $h{$k} and $h{$k};

(or how about print "'$k'\t'$h{$k}'\n" if exists $h{$k} and defined $h{$k} and $h{$k}; )

... then I would be wondering why you hadn't simply written

print "'$k'\t'$h{$k}'\n" if $h{$k}

I can understand sprinkling extra defined checks around reflexively from getting yelled at by the Perl warnings. Maybe that's all it's about, plus C programmer instinct to guard against access to an undefined element, analogous to if (p && *p != '\0') ... . In which case, criticizing that practice might be annoying.

I'll look more closely at your script tonight, J65nko. My manager just got after me to make progress on what I'm supposed to be working on.

$age{'Unborn'} fails the truth test because the number 0 is one of Perl's false values.

$age{'Phantasm'} only exists because it has been given a value in the hash. Because that value is 'undef' it does not pass the test for definedness.
'undef' is also a Perl false value.

And I'm saying that the pkg-config test's purpose is to look for toddlers to put in the pkg-path. That is, it spells out defined and not equal to blank (and also zero, so you can't put in a path of zero -- can't see that as a realistic need though) but if you view the cookbook example as a kind of truth table you can see that the defined test is redundant. It's only necessary to see if $ENV{VAR} is true before using it since not existing and existing as undef both evaluate to false.