in reply to Autovivification and hash slices

If you use a hash slice in lvalue context, Perl must create the elements of the slice in case they will actually be modified.

>perl -E"1 for @h{x}; say exists($h{x}) || 0; 1 >perl -E"sub {}->( @h{x} ); say exists($h{x}) || 0; 1 >perl -E"my $r = \@h{x}; say exists($h{x}) || 0; 1

The for loop might assign to $_ with the intention of changing $h{x}, so a copy can't be used.

The sub might assign to $_[0] with the intention of changing $h{x}, so a copy can't be used.

$$r must refer to $h{x}, so a copy can't be used.

As for join, it's a builtin operator (just like ("+"), not a sub call. Perl knows it doesn't need for lvalues, so it provide any. That's not the case for subs, though. Perl has no idea if the sub will pass values back by reference, so it much create lvalues just in case.

Sidebar

One exception!

>perl -E"1 for $h{x}; say exists($h{x}) || 0; 1 >perl -E"sub {}->( $h{x} ); say exists($h{x}) || 0; 0 >perl -E"\@h{x}; say exists($h{x}) || 0; 1

When a hash element (not a hash slice) is used as a sub argument, a special magical value is returned. Assigning to that magical value assigns to the hash. Getting a reference to magical value gets a reference to the hash element. Both of these cause the element's vivification, but not before. It's a bit slower to create and use this magical value, but it prevents a lot of accidental hash key vivifications.

The special magical value isn't returned for other lvalue contexts, and hash slices aren't coded to ever return these magical values.

To avoid vivification of the hash elements, you must avoid using the hash slice in lvalue context. You can do that by making copies of the values returned by the slice.

>perl -E"sub {}->( @{[ @h{x} ]} ); say exists($h{x}) || 0;" 0 >perl -E"sub {}->( do { @h{x} } ); say exists($h{x}) || 0;" 0

etc.

Replies are listed 'Best First'.
Re^2: Autovivification and hash slices
by norbert.csongradi (Beadle) on Aug 18, 2011 at 12:04 UTC
    Thank you very much, it clarifies it all :)