Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Is this a bug, or expected behavior?

by fizbin (Chaplain)
on Mar 17, 2006 at 15:07 UTC ( #537468=perlquestion: print w/replies, xml ) Need Help??

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

While working on an algorithm for finding polynomials to fit a bunch of points (which you can see on my scratchpad), I tripped across this little syntax quirk and wondered this behavior is expected, or possibly a bug in my perl (version 5.8.7, the stock cygwin build).

Namely, I found that this code:

use strict; my $a = [ qw(mary had a little lamb with mint jelly) ]; my $b = [ $a->[1..4] ]; my $c = [ @{$a}[1..4] ]; print "a is [ @$a ]\n"; print "b is [ @$b ]\n"; print "c is [ @$c ]\n";
produces this output:
a is [ mary had a little lamb with mint jelly ] b is [ mary ] c is [ had a little lamb ]

That is, $b is equal to [ $a->[0] ]. I cannot imagine how perl's syntax rules got there. Apparently, 1..4 is being evaluated in scalar context (despite the expression $a->[1..4] clearly being evaluated in a list context), and the result of scalar(1..4) is numerically equal to 0. This struck me as bizarre; I would have thought scalar(1..4) would be 4, not ''.

Is anyone else startled by this behavior?

--
@/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/

Replies are listed 'Best First'.
Re: Is this a bug, or expected behavior?
by Fletch (Bishop) on Mar 17, 2006 at 15:17 UTC

    Nope. .. in scalar context is a flip-flop operator. A constant expression on either side is compared against $.; since you've not read any lines of input $. does not equal 1, so it's evaluating to a false value 0.

    See perlop which explains all this in detail.

      Ah, right. Okay, so I can see why scalar(1..4) is ''; now my question is, why is 1..4 getting a scalar context above when I assign to $b? Shouldn't [ $a->[1..4] ] cause 1..4 to be evaluated in list context?
      --
      @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
        The context applied to $a->[1..4] does not affect how the subscript is being evaluated, or else we'd go crazy! It's always going to apply scalar context to the subscript, much as $a[EXPR] always applies scalar context to EXPR.

        If you want a single element, use the arrow notation. If you want a slice, use the slice notation. That's the way it works.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

        No, you're dereferencing a single element of an array reference. Dereferencing a slice from an array reference would, though.

        $ cat wa sub ctx { my $w = wantarray; if( defined $w ) { print $w ? "array\n" : "scalar\n"; } else { print "void\n" } 1; } my $a = [ qw( a b c ) ]; $a->[ ctx( ) ]; @{$a}[ ctx( ) ]; $ perl wa scalar array

        The [1..4] in list context is used with slices -- it doesn't create a list context on its own. Because you ask for $a->, you're telling Perl to dereference $a to a single element, not a slice, thus 1..4 is interpreted in scalar context.

        In the case that works, you're dereferencing $a to an array, and then taking a slice of that -- and because you're slicing, 1..4 gets interpreted in list context.

        $a->[1..4]; # not a slice @{$a}[1..4]; # slice

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        Unlike @{$a}[1..4], $a->[1..4] is not a array slice. This table should help you.
Re: Is this a bug, or expected behavior?
by BrowserUk (Patriarch) on Mar 17, 2006 at 15:38 UTC

    $a->[ 1.. 4 ] is not valid array slice syntax. You need an @ in there for it to be so:

    [0] Perl> $a = [ qw(mary had a little lamb with mint jelly) ];; [0] Perl> $b = [ @{ $a }[ 1 .. 4 ] ];; [0] Perl> print @$b;; had a little lamb

    I'm surprised that you didn't get a warning or two along the lines of:

    Using an array as a reference is deprecated at ... Argument "" isn't numeric in array element at ...

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Is this a bug, or expected behavior?
by QM (Parson) on Mar 17, 2006 at 15:19 UTC
    Tugging at the loose threads some more...
    my $b = [ $a->[1,2,3,4] ];
    gives a reference to an array with one element, undef.

    I'm guessing these are both edge cases in the dereference mechanism (->). Someone with more expertise than myself will have to look at the optree for these.

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      I would expect $a->[1, 2, 3, 4] to be the same as $a->[4], because the index is being evaluated in a scalar context, which means the comma is a "comma operator" (evaluate left expression, discard it, evaluate right expression). Correct?

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Yes, rigthly so.

        When I first checked this, I must have made a mistake, because it behaves exactly as you indicate.

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: Is this a bug, or expected behavior?
by timos (Beadle) on Mar 17, 2006 at 15:24 UTC
    if (1 .. 2) {print} and for (1 .. 2) {print} -- the same dots but different meaning :-)
    Regards,
    Timo
Re: Is this a bug, or expected behavior?
by rinceWind (Monsignor) on Mar 17, 2006 at 15:45 UTC

    To get a slice, you need to use the @ sigil on an array, and the subscript is evaluated in list context. Case $c is the correct way to do this.

    Case $b doesn't parse as a slice, but a single element dereference owing to the arrow. This forces scalar context on the subscript expression, turning your .. range operator into a flipflop operator, returning false (which is 0 in numeric context), hence the first element of @$a. In certain circumstances depending on the surrounding code, it could give you the second element, i.e. 'had'.

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)

Re: Is this a bug, or expected behavior?
by GrandFather (Saint) on Mar 17, 2006 at 18:21 UTC

    Heh, your basic problem is well answered. However, this was exactly the context that stimulated my meditation about the scalar range operator - you may be interested in reading Flipin good, or a total flop?.


    DWIM is Perl's answer to Gödel

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2022-08-10 18:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?