in reply to Re^8: searching a list
in thread searching a list

What is your solution? Using defined? Sorry, but that doesn't actually change anything. Really. IMO, you're sounding an alarm over nothing, and then offering a solution that not only doesn't solve any part of your original "problem" but offers distinctly different semantics.

$ perl -MData::Dumper -e 'my $h; $h->{x}++ if exists $h->{x}; print Du +mper($h)' $VAR1 = {}; $ perl -MData::Dumper -e 'my $h; $h->{x}++ if defined $h->{x}; print D +umper($h)' $VAR1 = {};
In both cases, %$h was autovivified. And $h->{x} was not. (I think in older perl5's, $h->{x} might have been autovivified and set to undef in the defined case, but never in the exists case ... unless I'm misremembering something.) The semantics, however, are different. If $h->{x} actually is undef, the exists will return true, while the defined will return false. Which is exactly what I don't want if all I want to do is test that the key exists. That's why we have different keywords - for different tests.

A value that doesn't exist is not defined. But a value that exists may still not be defined. Thus, two tests - one for exists, one for defined.

The proper solution to this quandary is to test each reference before dereferencing it:

if ($h and exists $h->{x})
or
if ($h and exists $h->{a} and exists $h->{a}{b} and exists $h->{a}{b}{ +foo})
This is the only way to keep $h->{a}{b} from being autovivified.

Replies are listed 'Best First'.
Re^10: searching a list (myth)
by tye (Sage) on Jun 27, 2006 at 18:48 UTC
    I think in older perl5's, $h->{x} might have been autovivified and set to undef in the defined case, but never in the exists case ... unless I'm misremembering something.

    No (yes, you are misremembering). Despite having seen many warnings for people to use defined and/or exists, these have never explicitly prevented autovivification. They can indirectly prevent autovivification by preventing a sneaky "lvalue context" situation, but they aren't special in this regard as just about any expression will do that as well, for example, " '' .... ". And, of course, nearly all of these cases of "wrapping in an expression" change the results. A possible exception is scalar, which prevents lvalue context while not changing the value returned (if dealing with a scalar expression, of course).

    So, sometimes you can avoid one level of autovivification by using a less direct expression, but:

    1. that only matters if you have an "lvalue context"
    2. what you use to gain this indirection mostly doesn't matter (exists or defined or scalar or lots of other things all work as well)
    3. you can't avoid the other levels of autovification this way

    I think at some point someone was pointed to insert a use of exists in order to gain a level of indirection such that $hash{key} would no longer be in an "lvalue context" and this advice got misinterpretted as exists having some magic power (or just an intentional feature) to prevent autovivification. That has never been the case. Though, there is talk of making exists special such that it can prevent more levels of autovivification (but I'm not holding my breath on that, personally).

    - tye        

Re^10: searching a list
by Corion (Patriarch) on Jun 27, 2006 at 14:54 UTC

    tye's conveniently packaged this "dive down but verify" process within Data::Diver

A reply falls below the community's threshold of quality. You may see it by logging in.