1

I have experienced strange behavior of using Regex captures for assignment of list elements - which puzzles me a lot, and I could not find an explanation anywhere in the documentation and other places. The code that I use is like this:

$_ = "one 1 two 2 three 3";
my $n = 1;
my @tt = (
    /one (\S+)/ ? (one => $1) : (),
    /two (\S+)/ ? (two => $1) : (),
    /three (\S+)/ ? (three => $1) : (),
);
print "Array: " . join(" ", @tt) . "\n";

Which prints, surprisingly:

Array: one 3 two 3 three 3

while I expect that it will print:

Array: one 1 two 2 three 3

So, when I use // and ?: within a list assignment, I always get captures from the last(!) matching expression - be it $1 or $& or anything else that refers to captures.

When I surround each ?: with do {}, everything works as expected, though.

My question is - what I am doing wrong? Is it a bug or some well known (or hidden) feature/behavior that I am not aware of?

Thank you!

PS: If this matters - I use standard perl 5.22.1 on Ubuntu 16.04.2, though the behavior is the same on Perl 5.8.8 and 5.24.1

EDIT: Though the reason for this behavior is the same as in this question - compilation order and post prefix opertors - but the context is quite different and it is not immediately obvious that questions are similar, as the previous question is about passing arguments to a sub, while in my question no subs are involved.

Community
  • 1
  • 1
aldem
  • 191
  • 11
  • To be honest, I doubt so - using () around every ternary operator, like "(/one (\S+)/ ? (one => $1) : ())" does not change a thing - it still takes the last expression... – aldem May 01 '17 at 20:58
  • the same underlying cause does not make this a duplicate question – ysth May 02 '17 at 00:05
  • 1
    But the fact that the answer is the same does, according to history. Closing a question doesn't prevent it from being found in searches; it prevents duplicate answers. – ikegami May 02 '17 at 00:25
  • @aldem, The other answer mentions that no subs are involved, giving `my @b = ($a, ++$a, $a++, $a);` as an example. – ikegami May 02 '17 at 13:18
  • 1
    @Håkon Hægland, Done. – ikegami May 02 '17 at 13:20
  • @ikegami I see your reasoning, though the other question may not be of immediate help for someone who is looking for similar issue. While I was searching for a cause, I knew that it was definitely not related to compilation/evaluation order nor post/infix operators - so I simply could not find it. Anyway, as long as the question is searchable, I hope it will be helpful to someone. – aldem May 02 '17 at 17:08
  • @aldem, I've already added the missing bits to the other answer. – ikegami May 02 '17 at 17:26

1 Answers1

4

The answer to compilation order and post prefix opertors also answers your question. What follows is a summary.


Generally speaking, avoid situations where you both set and read a variable within an expression[1].

Your code does the following:

  1. You set $1.
  2. You place a string and $1 on the stack. (Not a copy of $1!)
  3. You set $1.
  4. You place a string and $1 on the stack.
  5. You set $1.
  6. You place a string and $1 on the stack.
  7. You copy the contents of the stack (string, $1, string, $1, string, $1) into @tt. $1 is 3 at this point.

You can work around this by using "$1" instead of $1, since "$1" builds a new string from $1.


  1. That said, my $x = /(foo|bar)/ ? $1 : 'default'; would not have given you any problems.
Community
  • 1
  • 1
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Thank you - that was it! How could I forget that I am dealing with a reference here... :( – aldem May 01 '17 at 21:21
  • Could you not just do `my @tt = /(one|two|three) (\S+)/;` ? – Mark Reed May 02 '17 at 00:11
  • @Mark Reed, Maybe. The output would be different for `three 3 two 2 one 1`. – ikegami May 02 '17 at 13:15
  • @MarkReed Not really - one reason is mentioned by ikegami and my reason is that real code is a bit more complicated, like `my @tt = (/one (\S)/ ? foo($1) : "", /two (\S)/ ? bar($1) : "")`. – aldem May 02 '17 at 17:02
  • @aldem, If that's your code, you shouldn't have had any problems. – ikegami May 02 '17 at 17:08
  • @ikegami Well, it was even _more_ complicated :) In some cases there were function calls, but in some just expressions referring to $1 directly - that's why it puzzled me a lot - part of values were OK, while others were duplicates of the last one, so I reduced my sample to fragments which actually produced wrong results. – aldem May 02 '17 at 17:59