3

I've come across something odd while using a Perl script. It's about using a dot giving different results.

perlop didn't turn anything up, or perhaps I just blew past it. I was looking at Operator Precedence and Associativity

print "I'd expect to see 11x twice, but I only see it once.\n";
print (1 . 1) . "3";
print "\n";
print "" . (1 . 1) . "3\n";
print "Pluses: I expect to see 14 in both cases, and not 113, because plus works on numbers.\n";
print (1 . 1) + "3";
print "\n";
print "" + (1 . 1) + "3\n";

Putting quotes at the start is an acceptable workaround to get what I want, but what is happening here with the order of operations that I'm missing? What rules are there to be learned?

Community
  • 1
  • 1
aschultz
  • 1,658
  • 3
  • 20
  • 30
  • 1
    `perldoc perlfunc`: "Any function in the list below may be used either with or without parentheses around its arguments. (The syntax descriptions omit the parentheses.) If you use parentheses, the simple but occasionally surprising rule is this: It _looks_ like a function, therefore it is a function, and precedence doesn't matter." – Paul L May 31 '16 at 19:43

2 Answers2

14

When you put the first argument to print in parentheses, Perl sees it as function call syntax.

So this:

print (1 . 1) . "3";

is parsed as this:

print(1 . 1)  . "3";

or, equivalently:

(print 1 . 1) . "3";

Therefore, Perl prints "11", then takes the return value of that print call (which is 1 if it succeeded), concatenates 3 to it, and - since the whole expression is in void context - does absolutely nothing with the resulting 13.

If you run your code with warnings enabled (via -w on the command line or the use warnings; pragma), you will get these warnings identifying your error:

$ perl -w foo.pl
print (...) interpreted as function at foo.pl line 2.
print (...) interpreted as function at foo.pl line 6.
Useless use of concatenation (.) or string in void context at foo.pl line 2.
Useless use of addition (+) in void context at foo.pl line 6.

As Borodin points out in the comment below, you shouldn't rely on -w (or the in-code equivalent $^W); production code should always make use of the warnings pragma, preferably with use warnings qw(all);. While it wouldn't matter in this particular instance, you should also use strict;, although requesting modern features via useversion; for a Perl version of 5.11 or higher automatically turns on strict as well.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • Thanks! I use strict; use warnings; for bigger projects but with ten-liners or less I just hack through. So this question of mine is the tipping point for having a small template for all my new perl files big or small. that includes header comment and use strict;use warnings to catch problems like this. – aschultz Jun 02 '16 at 19:35
4

If a named operator (or a sub call) is followed by parens, those parens delimit the operands (or arguments).

print (1 . 1) . "3";       ≡  ( print(1 . 1) ) . "3";
print "" . (1 . 1) . "3";  ≡  print("" . (1 . 1) . "3");

Note that Perl would have alerted you of your problems had you been using (use strict; and) use warnings qw( all ); as you should.

print (...) interpreted as function at a.pl line 2.
print (...) interpreted as function at a.pl line 6.
Useless use of concatenation (.) or string in void context at a.pl line 2.
Useless use of addition (+) in void context at a.pl line 6.
I'd expect to see 11x twice, but I only see it once.
11
113
Pluses: I expect to see 14 in both cases, and not 113, because plus works on numbers.
11
Argument "" isn't numeric in addition (+) at a.pl line 8.
14
ikegami
  • 367,544
  • 15
  • 269
  • 518