http://www.perlmonks.org?node_id=379944

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

Hi, could somebody explain me why || and or have a different behaviour as in the example below ? Thank you very much.
use strict; use warnings; use Data::Dumper; my @array = (1,2,3,4); my @index = (1,3); &these(Index=>\@index); &those(Index=>\@index); sub these { my %args = @_; my @index = @{$args{Index}} || (); my $dump = Dumper($args{Index}); print "$dump"; $dump = Dumper(\@index); print "$dump"; } sub those { my %args = @_; my @index = @{$args{Index}} or (); my $dump = Dumper($args{Index}); print "$dump"; $dump = Dumper(\@index); print "$dump"; }

Replies are listed 'Best First'.
Re: Setting defaults in subroutines
by davorg (Chancellor) on Aug 04, 2004 at 09:43 UTC

    You're being burnt by a combination of operator precedence and context.

    my @index = @{$args{Index}} || ();

    is interpreted as

    my @index = (@{$args{Index}} || ());

    Then the || operator forces scalar context on @{$args{Index}} which therefore gives the number of elements in the array (which is 2).

    On the other hand,

    my @index = @{$args{Index}} or ();
    is interpreted as
    (my @index = @{$args{Index}}) or ();

    So the array is evaluated in list context and everything works as expected.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Pretty clear explaination. Thank you very much!
        The best way to see the precedence is to have a look at the cheat sheet, which shows this. I got confused with this myself a couple a weeks ago.

        Hans
Re: Setting defaults in subroutines
by PodMaster (Abbot) on Aug 04, 2004 at 09:45 UTC
    `perldoc perlop'
    C:\>perl -MO=Deparse,-p -e"die $a or $b" (die($a) or $b); -e syntax OK C:\>perl -MO=Deparse,-p -e"die $a || $b" die(($a || $b)); -e syntax OK C:\>

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Setting defaults in subroutines
by hv (Prior) on Aug 04, 2004 at 11:02 UTC

    Further to davorg's explanation, my usual idiom for getting the desired result is to move the default into the dereference:

    my @index = @{ $args{Index} || [] };

    This sidesteps the problem of @array || something forcing the array into scalar context, and also permits an undefined value.

    Hugo

      I agree. The best way to clarify your test and sidestep the precedence issue is to use parenthesis to explicitly describe how your test should be evaluated.
Re: Setting defaults in subroutines
by Fletch (Bishop) on Aug 04, 2004 at 13:02 UTC

    Rather than setting %args from @_ and then adding in defaults, I tend to use something along the lines of:

    sub foo { my @defaults = ( Index => [], weeble => "floop", ); my %args = ( @defaults, @_ ); for( @{ $args{ Index } } ) { ## ... } }

    You might also want to check out Params::Validate, which provides checking of parameters and allows you to specify default values where required.