Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Array/List Strangeness

by Manchego (Acolyte)
on Aug 04, 2009 at 16:32 UTC ( [id://785819]=perlquestion: print w/replies, xml ) Need Help??

Manchego has asked for the wisdom of the Perl Monks concerning the following question:

use Data::Dumper; { # This Makes sense: my @b; my @a=$b[0]; print Dumper(\@a); # $VAR1 = [ undef ]; } { # So does this: my @a = []->[0]; print Dumper(\@a); # $VAR1 = [ undef ]; } { # But this makes no sense (and seems like bug): my @a = ()[0]; print Dumper(\@a); # $VAR1 = [] }
Why should that last one return an empty list? I would expect an array of size 1 like the first 2 cases. Can someone please help shed some light on this? Thanks!

Replies are listed 'Best First'.
Re: Array/List Strangeness
by jwkrahn (Abbot) on Aug 04, 2009 at 16:52 UTC

    From perldata:

    A slice of an empty list is still an empty list. Thus: @a = ()[1,0]; # @a has no elements @b = (@a)[0,1]; # @b has no elements @c = (0,1)[2,3]; # @c has no elements
Re: Array/List Strangeness
by Taulmarill (Deacon) on Aug 04, 2009 at 20:41 UTC
    The difference is, that in the first two examples, you get an element of an array. In the last example you get an element from a list. Now every element of an array, which has not been set, is per default undef, since arrays in Perl have no limits. Lists are different, since lists are finite, they can return an empty list or a list shorter than the requested slice.
Re: Array/List Strangeness
by ikegami (Patriarch) on Aug 04, 2009 at 23:42 UTC

    Why should that last one return an empty list?

    Noone answered the question, and I'm also interested in knowing too. I don't know why they don't all behave one way or the other.

    If there's a reason to do it for list slices, the same reason exists for array slices. If there's no reason to do it for array slices, there's not reason to use it for list slices.

    Update: Added "slices" to avoid confusion.

      Most of the stuff about "a list" vs "an array" so far in this thread is just bull; making up stuff to explain observations without actually hitting on anything real.

      Perl has code that decides what to return when an array slice is done and it has code that decides what to return when a list slice is done. These different sections of code are not forced to return undef versus "nothing" based on some underlying difference in what an array is versus what a list is.

      The real reason why those sections of code were written to handle these cases differently is documented just below the already quoted section of the documentation (perldata):

      A slice of an empty list is still an empty list. Thus:

      @a = ()[1,0]; # @a has no elements @b = (@a)[0,1]; # @b has no elements @c = (0,1)[2,3]; # @c has no elements

      But:

      @a = (1)[1,0]; # @a has two elements @b = (1,undef)[1,0,2]; # @b has three elements

      This makes it easy to write loops that terminate when a null list is returned:

      while ( ($home, $user) = (getpwent)[7,0]) { printf "%-8s %s\n", $user, $home; }

      And I think it is easy to see that somebody is much less likely to write like:

      while( ( $home, $user )= @results[7,0] ) { ... }

      But I actually consider part of the documentation to be documenting a bug that was an accident of implementation. Quoting just the relevent parts:

      A slice of an empty list is still an empty list. Thus:

      @c = (0,1)[2,3]; # @c has no elements

      You see that @c is the result of a list slice of a non-empty list. The stated motivation explains why we want a list slice of an empty list to be empty (so that "failure" inside of the list slice gets communicated out to the "list assignment"). It doesn't explain why we want a slice of non-existent elements from the slicing of a list to magically disappear.

      Sure, making out-of-bounds elements of a list slice disappear is one way to implement things in order to get "a slice of an empty list is empty". But I'd rather the implementation not have such side effects. That is, I'd rather the slicing of a non-empty list treated out-of-bound elements consistently with how they are handled with array slices (and hash slices). Heck, the documented behavior for all-out-of-bounds items is even inconsistent with how list slices themselves behave:

      @d= (1,2,3)[9,1,8]; # @d= (undef,2,undef);

      I also believe that this behavior has changed subtly over the years. I know I've discussed/argued with Larry over this at least once.

      BTW, if you want to avoid this particular bit of magic, you can rewrite your list slice as an array slice: [get_a_list()]->[7,0]. And, as quietly noted in the documentation, if you want this behavior for an array slice, just write it as a list slice: (@array)[7,0].

      - tye        

        Talking about bull ;-)

        BTW, if you want to avoid this particular bit of magic, you can rewrite your list slice as an array slice: [get_a_list()]->[7,0]. And, as quietly noted in the documentation, if you want this behavior for an array slice, just write it as a list slice: (@array)[7,0].

        I am pretty sure that slicing while dereferencing with right-arrow isn't (yet) implemented in perl!

        DB<71> x [qw/a b c/]->[2] # works like expected 0 'c' DB<72> x [qw/a b c/]->[1,0] # oops! 0 'a' DB<73> x [qw/a b c/]->[0,1] 0 'b'

        Seems that instead to try slicing, the comma is interpreted in scalar context. Hence the last element of the slice-list is chosen as index!

        UPDATE: the only way I know to slice lists like arrays is:

        DB<83> x @{[ qw// ]}[0,1] 0 undef 1 undef DB<84> x @{[ qw/a b c/ ]}[0,1] 0 'a' 1 'b'

        Cheers Rolf

      For a Perl @var, two thing can happen:
      (a) @var is declared but does not exist in the sense that it is "empty", containing NO values, not even "undef".
      (b) @var is declared and does exist in the sense that it has "actual values" or undef as one or more values (undef is a value).

      my @var = (1,2,3);
      @var = (); # @var is "empty", NO values
      @var =undef; # @var has one value, undef

      Yes, this is weird that an @var can have "nothing" in it, not even undef. This @var=() is often seen in code that "zero'es" out a @variable.

      I have tried to avoid using the term "array" or "list" for these @vars. I remain curious as to when @var is an array and when @var is a list.

      Update: I prefer the word "list" for Perl @vars because a list can be empty. I don't think of an array as "empty". In my thinking, an array has a null element, null pointer, etc. But the idea that it is "empty", in the same sense that a list can be "empty" (like a completely blank "to-do list) doesn't make sense to me.

        Again, I know *what* is happening. The question is *why*. Why does requesting an non-existing array element return undef and requesting an non-existing list element return nothing.

        I have tried to avoid using the term "array" or "list" for these @vars. I remain curious as to when @var is an array and when @var is a list.

        @var is an array. It evaluates to a list in list context, just like every other operator.

      Noone answered the question, and I'm also interested in knowing too. I don't know why they don't all behave one way or the other.

      the "why" is explained in the docs, it's meant to produce a false value in a while loop.

      from perldata#Slices

      This makes it easy to write loops that terminate when a null list is returned: 1. while ( ($home, $user) = (getpwent)[7,0]) { 2. printf "%-8s %s\n", $user, $home; 3. }
      If there's a reason to do it for list slices, the same reason exists for array slices.

      The OP didn't use any array slices (jethro did). But I have to say I'm not happy with this non-orthogonality...

      UPDATE: IMHO there should be a special perldoc only for lists explaining the differences to arrays and how to avoid confusion...

      Cheers Rolf

Re: Array/List Strangeness
by biohisham (Priest) on Aug 04, 2009 at 23:21 UTC
    Besides numbers and strings scalar values can also hold the value undef, uninitialzied scalar variables have this value. It is interpreted as 0 in numeric context and as the empty string "" in string context. In other instances, like in subroutines, a return value of undef would indicate failure. In the third example you presented
    my @a = ()[0];
    jwkrahn mentioned a concept that fits the case since you are slicing an empty list but in the previous examples you are assigning conceptually nothing and hence undef is returned as the value of $VAR1.
    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind
Re: Array/List Strangeness
by jethro (Monsignor) on Aug 05, 2009 at 09:44 UTC

    Another two cases:

    { my @b; my @a = @b[1,0]; print Dumper(\@a); # $VAR1 = [ undef, undef ] } { my @b; my @a = (@b)[0]; print Dumper(\@a); # $VAR1 = [] }

    The first makes sure that it is not about slices vs. non-slices

    The second shows that it really is about lists vs. arrays. And also that it is an inconsistency that matters in real code (unlike the academic example ()[0] )

    The idiom is somewhat useful: my @a= (@b)[0..99]; would create a new array of max size 100, but won't make the new array larger if @b has fewer than 100 elements. And since there is probably code out there using this I don't think this inconsistency can be changed

      The idiom is somewhat useful: my @a= (@b)[0..99]; would create a new array of max size 100, but won't make the new array larger if @b has fewer than 100 elements. And since there is probably code out there using this I don't think this inconsistency can be changed

      I don't know what you mean, can't see any general difference between slicing @b or (@b), except when $#b==0!

      DB<38> @b=1..3 DB<39> x @b[0..6] 0 1 1 2 2 3 3 undef 4 undef 5 undef 6 undef DB<40> x (@b)[0..6] 0 1 1 2 2 3 3 undef 4 undef 5 undef 6 undef

      now 0-element array!

      DB<43> @b=() DB<44> x @b[0..6] 0 undef 1 undef 2 undef 3 undef 4 undef 5 undef 6 undef DB<45> x (@b)[0..6] empty array

      Cheers Rolf

        Look at the time the node was posted, it was when I still had hope ;-) and no indication of further inconsistent behaviour

        You have to make all of the elements referenced out-of-bounds. Compare @b[@b,1+@b] vs (@b)[@b,1+@b] (whether @b is empty or not).

        - tye        

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://785819]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-16 21:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found