>   > > exists  (sometimes causes autovivification, which affects C<keys>)
>   > 
>   > That's not technically accurate--exists never causes autovivification.  

>       print keys %hash, "\n";
>       exists $hash{key}{subkey};
>       print keys %hash, "\n";

>Or did that get fixed when I wasn't looking?

No, the -> operator has not been changed to do lazy evaluation.

>(And yes, of course I know the distinction that makes you techically
>correct, but I don't think it is germane to this argument :-)

I just don't like reading "exists causes autovivification" when it doesn't.
If it did, then 

    exists $hash{key}

would trigger this--but it doesn't.  It's the act of dereferencing
indiscriminate of L/R-value context that does this.  And given that
subroutines' args are lvaluable, it will take a serious hack to 
change this.  Even the tricks needed to make

    fn( $a[3] )

not autovivify was long in coming.

--tom

Random camel droppings on this matter follow for those who would
contemplate an RFC about it.

On References:

    This is one of those cases mentioned earlier in which references spring
    into existence (or "autovivify") when used as an lvalue (that is, when
    a value is being assigned to it).  Supposing C<$array[3]> to have been
    undefined, it's automatically defined as a hash reference so that we
    can set a value for C<< $array[3]->{"English"} >> in it.  Once that's
    done, C<< $array[3]->{"English"} >> is automatically defined as an
    array reference so that we can assign something to the first element in
    that.  Note that rvalues are a little different: C<print
    $array[3]->{"English"}->[0] >> only defines C<$array[3]> and C<<
    $array[3]->{"English"} >>, not C<< $array[3]->{"English"}->[0] >>,
    since the final element is not an lvalue.  (The fact that it defines
    the first two at all in an rvalue context could be considered a bug.
    We may fix that someday.)

On Operators:

    Just as in C and C++, the binary C<< -> >> operator is an infix
    dereference operator.  If the right side is a C<[...]> array
    subscript, a C<{...}> hash subscript, or a C<(...)> subroutine
    argument list, the left side must be a reference (either hard
    or symbolic) to an array, a hash, or a subroutine, respectively.
    In an lvalue (assignable) context, if the left side is not a
    reference, it must be a location capable of holding a hard
    reference, in which case such a reference will be I<autovivified>
    for you.  For more on this (and some warnings about accidental
    autovivification) see L<Chapter ##, References>.

On Functions under exists():

    R<EXPR> can be arbitrarily complicated, provided that the final
    operation is a hash key or array index lookup:

        if (exists $hash{A}{B}{$key}) { ... }

    Although the last element will not spring into existence just
    because its existence was tested, intervening ones will.  Thus
    C<< $$hash{"A"} >> and C<< $hash{"A"}->{"B"} >> will both spring
    into existence.  This is not a function of C<exists>, I<per
    se>; it happens anywhere the arrow operator is used (explicitly
    or implicitly):

        undef $ref;
        if (exists $ref->{"Some key"}) { }
        print $ref;   # prints HASH(0x80d3d5c)

    Even though the C<"Some key"> element didn't spring into
    existence, the previously undefined C<$ref> variable did suddenly
    come to hold an anonymous hash.  This is a surprising instance
    of I<autovivification> in what does not at first--or even
    second--glance appear to be an lvalue context.  This behavior
    is likely to be fixed in a future release.  As a workaround,
    you can nest your calls:

        if ($ref                        and
            exists $ref->[$x]           and
            exists $ref->[$x][$y]       and
            exists $ref->[$x][$y]{$key} and
            exists $ref->[$x][$y]{$key}[2] ) { ... }

Reply via email to