Autovivification by foreach

F

Frank Seitz

Hi,

given the following code:

use strict;
use warnings;

my (@a,$ref);
push @a,@$ref;

Perl throws an exception:
Can't use an undefined value as an ARRAY reference
Seems plausible.

We are modifying the code:

my (@a,$ref);
push @a,$_ for @$ref;

Now, there is no exception anymore. Perl creates the array on the fly.
Why is it so? What is the difference?

Frank
 
U

Uri Guttman

FS> my (@a,$ref);
FS> push @a,@$ref;

FS> Perl throws an exception:
FS> Can't use an undefined value as an ARRAY reference
FS> Seems plausible.

FS> We are modifying the code:

FS> my (@a,$ref);
FS> push @a,$_ for @$ref;

FS> Now, there is no exception anymore. Perl creates the array on the fly.
FS> Why is it so? What is the difference?

in the first case @$ref is readonly as it is input to push and can't be
modified. autovivification only happens on lvalues when they are undef
and used where a ref should be.

on the other hand for (modifier or main loop style) makes $_ an alias
into each element of its list. and $_ is read/write so the elements
should be lvalues. so perl will autovivify the array ref since you might
be modifying elements. it can't tell (the executed code could be a sub
call, etc.) so it has to do this before the loop starts. this little
test shows what happens:

perl -le 'push @a,$_ for @$ref; print $ref'
ARRAY(0x8163248)

for much more on autoviv read my tutorial:

http://sysarch.com/Perl/autoviv.txt

uri
 
F

Frank Seitz

Uri said:
FS> my (@a,$ref);
FS> push @a,@$ref;

FS> Perl throws an exception:
FS> Can't use an undefined value as an ARRAY reference
FS> Seems plausible.

FS> We are modifying the code:

FS> my (@a,$ref);
FS> push @a,$_ for @$ref;

FS> Now, there is no exception anymore. Perl creates the array on the fly.
FS> Why is it so? What is the difference?

in the first case @$ref is readonly as it is input to push and can't be
modified. autovivification only happens on lvalues when they are undef
and used where a ref should be.

Thanks, the readonly/lvalue distinction in this context was not clear to me.
on the other hand for (modifier or main loop style) makes $_ an alias
into each element of its list. and $_ is read/write so the elements
should be lvalues. so perl will autovivify the array ref since you might
be modifying elements. it can't tell (the executed code could be a sub
call, etc.) so it has to do this before the loop starts.

This explanation is not plausible to me. Perl autovivifies before
loop start, because the loop might be modifying array elements?
How is this possible? The autovivificated array is empty.
It is clear that the body of the loop is never executed.

In my opinion it would make more sense when Perl would
throw an exception in this case too.

Frank
 
A

A. Sinan Unur

....

This explanation is not plausible to me. Perl autovivifies before
loop start, because the loop might be modifying array elements?
How is this possible? The autovivificated array is empty.
It is clear that the body of the loop is never executed.

In my opinion it would make more sense when Perl would
throw an exception in this case too.

First, note that I do think this behavior is a little quirky.

However, it seems to me that autovivification in this context is useful.

It allows you to avoid writing code to check $ref before, say, adding
elements to some array for further processing. In that context, one may
not care about the definedness of $ref per se but only about if it
points to further elements to process.

Uri's explanation made sense to me. Hash element autovivification has
its quirks too but it is useful under similar circumstances.

If you don't want autovivification and you want to avoid the exception,
you can write:

push @a, @$ref if ref $ref eq 'ARRAY';

Or, if you want the exception, write:

die '$ref is not defined' unless defined $ref;
die '$ref is not an array ref' unless ref $ref eq 'ARRAY';

Sinan

--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
U

Uri Guttman

FS> This explanation is not plausible to me. Perl autovivifies before
FS> loop start, because the loop might be modifying array elements?
FS> How is this possible? The autovivificated array is empty.
FS> It is clear that the body of the loop is never executed.

if perl didn't autovivify the lvalue in the for loop, then it would die
if you attempted to modify an array ref element. perl assumes that since
the array ref being used (and it is undef) is an lvalue then you
may/will write to it so it autovivifies for you.

FS> In my opinion it would make more sense when Perl would
FS> throw an exception in this case too.

it doesn't because of DWIM. autovivification is a subtle thing at times
and very useful most of the time. it does have some edges like deep
access using exists will autovivify. perl6 fixed that problem. maybe it
could not autovivify the array ref unless an element is modified but i
can live with that as it is.

uri
 
P

Peter J. Holzer

FS> This explanation is not plausible to me. Perl autovivifies before
FS> loop start, because the loop might be modifying array elements?
FS> How is this possible? The autovivificated array is empty.
FS> It is clear that the body of the loop is never executed.

if perl didn't autovivify the lvalue in the for loop, then it would die
if you attempted to modify an array ref element.

You can't attempt to do that since the loop body is never executed.

hp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top