Logical or assignment and array

Discussion in 'Perl Misc' started by Adrien BARREAU, Jan 14, 2014.

  1. Hello all.


    Here is a piece of code that troubles me:

    =====
    $ perl -e 'my @a; @a = @a || 1..3;'
    $ perl -e 'my @a; @a ||= 1..3;'
    Can't modify private array in logical or assignment (||=) at -e line 1,
    near "3;"
    Execution of -e aborted due to compilation errors.
    =====

    It thought the "a operator= b" notation really was "a = a operator b",
    but it seems it is wrong.

    Does anyone have some information about this?


    Adrien.
     
    Adrien BARREAU, Jan 14, 2014
    #1
    1. Advertisements

  2. Στις 14/1/2014 13:01, ο/η Adrien BARREAU έγÏαψε:



    it have to do with left/right precedence the following works


    my @a;
    @a = qw/a b/;
    @a or @a=1..3;

    $,="\n"; print @a;
     
    George Mpouras, Jan 14, 2014
    #2
    1. Advertisements

  3. I doubt that this expression means what the OP thinks it means, cf

    perl -e '@b = (4,5,6); @a = @b || 1 .. 3; print @a;'

    This prints 3 because evaluating @b in scalar context returns the size
    of the array.
    The @a in @a ||= parses as OP_RV2AV and the Perl_mod routine in op.c
    (5.10.1) which is used to

    Propagate lvalue ("modifiable") context to an op and its
    children. 'type' represents the context type, roughly based on
    the type of op that would do the modifying, although local() is
    represented by OP_NULL. It's responsible for detecting things
    that can't be modified,

    type is OP_ASSIGN which is classifed as 'scalar mod type' by the
    function of the same name and Perl_mod rejects the assignment because of
    that.

    Logically, one could regard this as '@a evaluated in scalar context', as
    required by the || part of ||=, yields the size of a and since this is
    an integer constant, it can't be assigned to.
     
    Rainer Weikusat, Jan 14, 2014
    #3
  4. I doubt that this expression means what the OP thinks it means, cf

    perl -e '@b = (4,5,6); @a = @b || 1 .. 3; print @a;'

    This prints 3 because evaluating @b in scalar context returns the size
    of the array.
    The @a in @a ||= parses as OP_RV2AV and the Perl_mod routine in op.c
    (5.10.1) which is used to

    Propagate lvalue ("modifiable") context to an op and its
    children. 'type' represents the context type, roughly based on
    the type of op that would do the modifying, although local() is
    represented by OP_NULL. It's responsible for detecting things
    that can't be modified,

    type is OP_ORASSIGN which is classifed as 'scalar mod type' by the
    function of the same name and Perl_mod rejects the assignment because of
    that.

    Logically, one could regard this as '@a evaluated in scalar context', as
    required by the || part of ||=, yields the size of a and since this is
    an integer constant, it can't be assigned to.
     
    Rainer Weikusat, Jan 14, 2014
    #4
  5. [...]
    Remotely Enlish variant: "The Perl_mod routine which is used to [...]
    rejects the assignment because the type is [...] which is [...]"
     
    Rainer Weikusat, Jan 14, 2014
    #5
  6. Adrien BARREAU

    Tim McDaniel Guest

    The first time, I misread what you actually wrote. The second
    occurrence of @a in the whole line (the first operand of ||) is
    evaluated in a scalar context. 1..3 (the second operand of ||) as
    stated in "man perlop" should be evaluated in a list context:

    C-style Logical Or

    Binary "||" performs a short-circuit logical OR operation.
    That is, if the left operand is true, the right operand is
    not even evaluated. Scalar or list context propagates down
    to the right operand if it is evaluated.
     
    Tim McDaniel, Jan 14, 2014
    #6
  7. Adrien BARREAU

    Tim McDaniel Guest

    that is, trying to do this

    @a = @a || 1..3;

    to mean "if @a has no elements, supply defaults", only works if @a has
    no elements.

    I've certainly used the scalar version,

    $arg ||= 'default';

    A pity that it doesn't work for arrays. Is there a nice concise way
    to do it for arrays?

    @a = 1..3 if !@a;

    @a = @a ? @a : 1..3;

    Neither of those is quite as nice.
     
    Tim McDaniel, Jan 14, 2014
    #7
  8. @a or @a = 1 .. 3

    or

    !@a and @a = 1 .. 3

    would be two other options.
     
    Rainer Weikusat, Jan 14, 2014
    #8
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.