in reply to question about || operator and list context

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


Replies are listed 'Best First'.
Re: Re: question about || operator and list context
by markjugg (Curate) on Jun 22, 2003 at 04:14 UTC
    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


Re^2: question about || operator and list context
by Aristotle (Chancellor) on Jun 22, 2003 at 13:27 UTC
    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.