Autovivification by foreach

Discussion in 'Perl Misc' started by Frank Seitz, Mar 12, 2009.

  1. Frank Seitz

    Frank Seitz Guest

    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
    --
    Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
    Anwendungen für Ihr Internet und Intranet
    Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
     
    Frank Seitz, Mar 12, 2009
    #1
    1. Advertising

  2. Frank Seitz

    Uri Guttman Guest

    >>>>> "FS" == Frank Seitz <> writes:

    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

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, Mar 12, 2009
    #2
    1. Advertising

  3. Frank Seitz

    Frank Seitz Guest

    Uri Guttman wrote:
    >>>>>> "FS" == Frank Seitz <> writes:

    >
    > 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
    --
    Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
    Anwendungen für Ihr Internet und Intranet
    Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
     
    Frank Seitz, Mar 13, 2009
    #3
  4. Frank Seitz <> wrote in
    news::

    > Uri Guttman wrote:
    >>>>>>> "FS" == Frank Seitz <> writes:

    >>
    >> 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.

    >


    ....

    > 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 <>
    (remove .invalid and reverse each component for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://www.rehabitation.com/clpmisc/
     
    A. Sinan Unur, Mar 13, 2009
    #4
  5. Frank Seitz

    Uri Guttman Guest

    >>>>> "FS" == Frank Seitz <> writes:

    >> 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.


    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

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, Mar 13, 2009
    #5
  6. On 2009-03-13 15:54, Uri Guttman <> wrote:
    >>>>>> "FS" == Frank Seitz <> writes:
    > >> 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.

    >
    > 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
     
    Peter J. Holzer, Mar 14, 2009
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kevin Spencer

    Re: foreach loop error

    Kevin Spencer, Aug 22, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    371
    Kevin Spencer
    Aug 22, 2003
  2. Luc Kumps

    Re: foreach loop error

    Luc Kumps, Aug 22, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    389
    Luc Kumps
    Aug 22, 2003
  3. John Carter
    Replies:
    1
    Views:
    111
    gabriele renzi
    Dec 1, 2003
  4. Replies:
    7
    Views:
    142
    Brad Baxter
    May 15, 2006
  5. sm
    Replies:
    1
    Views:
    87
    DJ Stunks
    Jan 4, 2007
Loading...

Share This Page