Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

question about || operator and list context

by markjugg (Curate)
on Jun 22, 2003 at 01:54 UTC ( [id://267897]=perlquestion: print w/replies, xml ) Need Help??

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

Just when I thought I understand the || operator, I've run into a case I don't fully understand. Could someone explain why Perl is working like this? This is with Perl 5.8.

# 1. with extra parens, works as expected (($a,$b) = (qw/a b/)) || die; print "a: $a b: $b\n "; # 2. without || or parens, works as expected ($a,$b) = (qw/a b/); print "a: $a b: $b\n "; # 3. without parens, but with ||, $a is set to 'b' # and $b is not set. Why? ($a,$b) = (qw/a b/) || die; print "a: $a b: $b\n ";
Thanks!

Mark

Replies are listed 'Best First'.
Re: question about || operator and list context
by Aristotle (Chancellor) on Jun 22, 2003 at 02:10 UTC
    The third case reads to Perl like so:
    ($a,$b) = ( qw/a b/ || die );

    Note that the || gets to be evaluated first. Since the boolean logic operators force scalar context on their left hand operand, which in this case is a list, you get what a list returns when coerced into scalar context: its last element. This is the string b here. Because it is is a true value, it shortcircuits the or-operator and so prevents die from being called. Now we get to the assignment, with just a single value in hand. The $a slurps it up, and $b is left with nothing to take.

    By changing the order of evaluation with an extra pair of parens, you can make sure the or-operator doesn't coerce the wrong thing into scalar context - just like you did in your case #1.

    Makeshifts last the longest.

Re: question about || operator and list context
by japhy (Canon) on Jun 22, 2003 at 02:19 UTC
    Well, let's get qw() out of the picture.
    # the equals operator happens first (($a, $b) = ('a', 'b')) || die; # eh, who cares? ($a, $b) = ('a', 'b'); # the || happens first, and enforces # SCALAR CONTEXT on ('a', 'b'), which # means it returns the right-most element ($a, $b) = ('a', 'b') || die;

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: question about || operator and list context
by converter (Priest) on Jun 22, 2003 at 03:32 UTC

    Just because I find the subject of lists and the comma operator interesting (and I'm trying to avoid real work for a few minutes):

    Compare the outputs of the following assignment expressions:

    sub context { print defined wantarray ? wantarray ? "list" : "scalar" : "void" , "\n"; $_[0]; } ($a, $b) = (context('a'), context('b')); print "a=[$a],b=[$b]\n\n"; ($a, $b) = (context('a'), context('b')) || die "foo"; print "a=[$a],b=[$b]\n"; list list a=[a],b=[b] void scalar a=[b],b=[]

    It appears to me that in the second case the comma is acting as a scalar comma expression and not a list. Granted, || is a binary, not a unary operator, but I find the following description of context supplied in comma expressions interesting:

    from the perl 5.8 perlfunc scalar() section: Because "scalar" is unary operator, if you accidentally use for EXPR a parenthesized list, this behaves as a scalar comma expression, evaluating all but the last element in void context and returning the final element evaluated in scalar context. This is seldom what you want.

    Example:

    $c = scalar(context('a'), context('b')); print "$c\n"; void scalar b
    conv
Re: question about || operator and list context
by BrowserUk (Patriarch) on Jun 22, 2003 at 03:53 UTC

    I realise that your example is just that, but it is a strange choice of example. More to the point, even with the extra parens, it is a somewhat dangerous one.

    I can only assume that the idea is that you die unless your vars $a and $b (not great choices in themselves.. see perlfunc:sort) get set to "some values". Now, in the example, the values in question are constants, which is pretty unlikely to fail, but it is just an example.

    So, making a guess as to the context in which you made your discovery, you probably had something like this

    ( ($a, $b) = ( $somevar, $someothervar ) ) || die '$somevar or $someot +hervar not set!'; ...

    However, I wonder if you realise exactly what it is that you are testing with this construct?

    Try and guess which of the following pairs of values being assigned will result in the warning being issued, then run the code.

    #! perl -slw use strict; for( ['a', 'b'], [1, 2], [0, 1], ['a', 'b'], [undef, undef], [1, undef], [undef, 1], [ ] #Intentionally empty. ) { my($a,$b); (($a, $b) = ( $_->[0], $_->[1] )) || warn "I would die when \$a=$a and \$b=$b\n"; }

    Did you try it? Were you right? Surprising isn't it:)

    ps. I wonder how many of the others posters above will be surprised too?


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      Since you were curious, here's the (fixed) real world code:

      use File::Temp (qw/tempfile/); (($fh,$fname) = tempfile('quanta-XXXX')) || die "Couldn't create temp file $fname\n";

      The results without the extra parens differed a bit from the example above, though. $fh got set to a GLOB (a filehandle, I assume). This is the /first/ element in the array return, not the last.

      I understand why that is now, though-- the || forced the subroutine to scalar context, in which it just returns a filehandle.

      This made it more mysterious to debug though, since it wasn't returning just the last element of the array, which I might have recognized sooner.

      Thanks to all for your help.

      Mark

        In this case, I would strongly favour using or instead of '||'. It removes the need for the extra parens and is (IMO) visually cleaner too.

        use File::Temp (qw/tempfile/); ($fh,$fname) = tempfile('quanta-XXXX') or die "Couldn't create temp file $fname\n";

        The (deliberately) much lower precedence of or means that it acts as an effective seperator between list contexts and in so doing, removes the need for a lot of otherwise necessary punctuation. TIMTOWTDI:)


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      I wonder if you realise exactly what it is that you are testing with this construct? :)
      use strict; use warnings; $" = '+'; for( ['a', 'b'], [1, 2], [0, 1], ['a', 'b'], [undef, undef], [1, undef], [undef, 1], [ ], ) { print "\@\$_ is @$_\n"; (my ($foo, $bar) = @$_) || print "I would die here\n"; print "\n"; }
      You see, once you actually treat an array as a container of a list, rather than treating it as a list of scalar elements, then all of a sudden it becomes clear what he was testing for. A list with two undefined elements is not an empty list; it is a list with two undefined elements. In real world examples, instead of @$_ one would be using a function call (as the OP eventually demonstrated in his other post), much like the common while(my ($k, $v) = each %hash) { } idiom. This will not abort looping on pairs such as '' => undef because that is not an empty list - it will continue running until, when each reaches the end of the hash, it receives an actual empty list.

      Makeshifts last the longest.

Re: question about || operator and list context
by bobn (Chaplain) on Jun 22, 2003 at 04:37 UTC
    The 3rd case works if you use 'or die' instead of '|| die'.

    'or' has much lower precendence than '||' and for that reason is often the better choice.

    --Bob Niederman, http://bob-n.com

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2024-04-25 08:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found