> > > 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] ) { ... }