2

I have the following code:

$codelist = 00;

$OK = '0';
$OK = () = $codelist =~ /$OK/g;

print "$OK\n"; #answer is 2.

How does the expression $OK = () = $codelist =~ /$OK/g is evaluated? What is the order of precedence?

Grinnz
  • 9,093
  • 11
  • 18

3 Answers3

5

B::Deparse can show you precedence if you ever get confused.

$ perl -MO=Deparse,-p -e '$OK = () = "00" =~ /0/g'
($OK = (() = ('00' =~ /0/g)));
-e syntax OK
Possum
  • 537
  • 3
  • 11
mob
  • 117,087
  • 18
  • 149
  • 283
4

If you look at perldoc perlop, there is the following precedence chart:

left        terms and list operators (leftward)
left        ->
nonassoc    ++ --
right       **
right       ! ~ \ and unary + and -
left        =~ !~
left        * / % x
left        + - .
left        << >>
nonassoc    named unary operators
nonassoc    < > <= >= lt gt le ge
nonassoc    == != <=> eq ne cmp ~~
left        &
left        | ^
left        &&
left        || //
nonassoc    ..  ...
right       ?:
right       = += -= *= etc. goto last next redo dump
left        , =>
nonassoc    list operators (rightward)
right       not
left        and
left        or xor

From that chart, we look up =~ and = because those are the only operators you have here.

=~ is tighter binding, so that gets evaluated first $OK = () = ($codelist =~ /$OK/g);

Then =in left order...

($OK = () = ($codelist =~ /$OK/g));
($OK = (() = ($codelist =~ /$OK/g)));

Another helpful tool mentioned in other answers is B::Deparse with the -p option. Still, it is a good idea to be familiar with the above chart, or at least know where to reference it.

As a side note, the =()= is a somewhat common idiom, so much so that it has an entry in the perlsecret distribution as the "Goatse" (don't Google that) or "Saturn" secret operator; it is essentially used to force list context to the right side, usually to return the count (since the left side is a scalar).

Possum
  • 537
  • 3
  • 11
1

I assume your example-code starts with

$codelist = '00';

The code

$OK = () = $codelist =~ /$OK/g;

first matches $codelist against 0 globally so it returns ALL matches. But that is only true, when called in a list-context. Otherwise, it would only return whether it matches or not. The assignment-trick with

$OK= () = ...

sets the list-context for the evaluation and evaluates the returned array in the scalar context (which results in the number of elements).

So when you remove the /g in the match, or the () = in the assingement you get 1.

Georg Mavridis
  • 2,312
  • 1
  • 15
  • 23
  • Re "*evaluates the returned array in the scalar context*", That is wrong. 1) The match op returns a number of scalars, not an array. 2) Only *operators* are evaluated, not *values*. Converting a value is called *casting*, not *evaluating*. And casting into scalar context isn't a thing Perl ever does. What is really happening is that the *list assignment* is being evaluated in scalar context, which causes it to return the number of scalars returned by its RHS. See [Scalar vs List Assignment Operator](https://stackoverflow.com/a/54564429/589924) for more details – ikegami Mar 05 '20 at 23:13
  • According to your explanation, `my @a = localtime; say scalar(@a);` and `say scalar(localtime);` should both output the same thing, but they don't. – ikegami Mar 05 '20 at 23:19
  • about 1) try ```perl -MData::Dumper -e "print Dumper ['0sdfsadfaf0'=~/./g]"``` – Georg Mavridis Mar 06 '20 at 11:43
  • What about it? `[]` creates an array populated by the scalars returned by the match operator, it creates a reference to the array, and it returns the reference. `Dumper` is called to create a string from that reference, the referenced array, and the scalars within. That string is printed to STDOUT by `print`. What part of that has anything to do with what I said? – ikegami Mar 06 '20 at 11:48
  • I meant: "the match op (in list context) does not return a number." Obviously we have a language problem. What I meant is: The match-op with the /g modifier specifies global pattern matching--that is, matching as many times as possible within the string. How it behaves depends on the context. In list context, it returns a list of the substrings matched by any capturing parentheses in the regular expression. If there are no parentheses, it returns a list of all the matched strings, as if there were parentheses around the whole pattern. (citing from https://perldoc.perl.org/perlop.html) – Georg Mavridis Mar 06 '20 at 12:06