in reply to Why Perl gets confused here?

You made two changes. You removed the parens around the arguments, and you added parens around substr. The former is inconsequential here, so let's start by reverting it to make things clearer. This means you have

... substr( $p, 0, 1 ) = '123' ... ... ( substr( $q, 0, 1 ) ) = '123' ...

There are two different assignment operators: the scalar assignment operator and the list assignment operator.

To which operator = compiles is determined by the left-hand side (LHS) of the operator. If the LHS look "list-ish", a list assignment operator will be used. Otherwise, a scalar assignment operator will be used.

In the first case, the LHS of the assignment is subtr(...). That's not "list-ish", so a scalar assignment operator is used. A scalar assignment operator in scalar context[1] returns its LHS, so this assignment evaluates the result of substr.

In the second case, the LHS of the assignment is ( ... ). That is "list-ish", so a list assignment operator is used. A list assignment operator in scalar context[1] returns the number of scalars to which its RHS evaluates, so this assignment evaluates to (a fresh scalar with value) 1.

The following is a variant of your code that allows us to check the values returned by the assignments.

use strict; use warnings; use feature 'say'; my $p = 'abc'; my $q = 'abc'; my $ref_p = \scalar( substr( $p, 0, 1 ) = '123' ); my $ref_q = \scalar( ( substr( $q, 0, 1 ) ) = '123' ); say $$ref_p; # 123 say $$ref_q; # 1 substr( $$ref_p, 0, 1 ) = 'x'; substr( $$ref_q, 0, 1 ) = 'x'; say $$ref_p; # x23 say $$ref_q; # x say $p; # x23bc say $q; # 123bc

Reference: Mini-Tutorial: Scalar vs List Assignment Operator

  1. substr evaluates its first operand in scalar context.

Replies are listed 'Best First'.
Re^2: Why Perl gets confused here?
by vr (Curate) on Oct 27, 2017 at 13:49 UTC

    Thank you for explanation.

    use strict; use warnings; use feature 'say'; use Devel::Peek; my $p = 'abc'; my $q = 'abc'; Dump(( substr $p, 0, 1 ) = '123' ); Dump( time ); (( substr( $q, 0, 1 )) = '123' ) = 'x'; say $q; #substr(( time ), 0, 1 ) = 'x';

    SV = IV(0xa72034) at 0xa72034 REFCNT = 1 FLAGS = (PADTMP,IOK,pIOK) IV = 1 SV = IV(0xa8bb44) at 0xa8bb44 REFCNT = 1 FLAGS = (PADTMP,IOK,pIOK) IV = 1509111305 xbc

    Shouldn't the return value of list assignment operator be treated as constant, then? I tried to "sneak" various types of constants or constant-producing expressions as arg to lvalue-substr, but Perl reports compile time error (commented line).

    More confusing is "xbc" -- I'd expect $q to be "123bc", and "x" to be gone into fathomless void, as in OP?

      Context matters.

      This is list context  (( substr( $q, 0, 1 )) = '123' ) = 'x';

      But the OP happened in scalar context, see Ikegami's footnote.

      "substr evaluates its first operand in scalar context."

      > More confusing is "xbc" -- I'd expect $q to be "123bc", and "x" to be gone into fathomless void, as in OP?

      Depending on your Perl version you can assign multiple times to the same lvalue.

      in this case first 123 then x

      See substr documentation

      Note that the lvalue returned by the three-argument version of substr acts as a 'magic bullet'; each time it is assigned to, it remembers which part of the original string is being modified

      To avoid confusion, I'd suggest using the 4 parametric version instead of the lvalue variant.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!