How does Perl handle the chain of statements?

So, I have this bit of code that does not work:

print $userInput."\n" x $userInput2; #$userInput = string & $userInput2 is a integer 

It prints it once perfectly, of course, if the number is greater than 0, but it does not print the rest, if the number is greater than 1. I come from the java background, and I assume that it concatenates first, then the result will be that it will multiply to the operator x . But of course this does not happen. Now it works when I do the following:

 $userInput .= "\n"; print $userInput x $userInput2; 

I am new to Perl, so I would like to understand exactly what is happening with the chain, and even if I can do it.

+4
source share
3 answers

You are asking about operator priority. (A "chain" usually refers to a chain of method calls, for example $obj->foo->bar->baz .)

The Perl perlop documentation page starts with a list of all statements in order of priority. x has the same priority as other multiplication operators, as well . has the same priority as other addition operations, so of course x is evaluated first. (that is, "has a higher priority" or "binds more tightly.")

As in Java, you can resolve this with parentheses:

 print(($userInput . "\n") x $userInput2); 

Note that here you need two pairs of parentheses. If you used only internal brackets, Perl would consider them as an indication of print arguments, for example:

 # THIS DOESN'T WORK print($userInput . "\n") x $userInput2; 

This will print the line once, and then duplicate print return value several times. Putting a space before ( does not help, since spaces are usually optional and are ignored. In some ways, this is another form of operator precedence: function calls are linked more closely than anything else.

If you really hate more brackets than strictly necessary, you can defeat Perl with the unary + operator:

 print +($userInput . "\n") x $userInput2; 

Separates print from ( , so Perl knows that the rest of the string is a single expression. Unary + has no effect; its main use is just this situation.

+8
source

This is because the priority of the operator <<20> (concatenation) is less than the operator x . Thus it ends:

 use strict; use warnings; my $userInput = "line"; my $userInput2 = 2; print $userInput.("\n" x $userInput2); 

And outputs:

 line[newline] [newline] 

Is this what you want:

 print (($userInput."\n") x $userInput2); 

This produces:

 line line 
+4
source

As already mentioned, this precedence problem is that the repetition operator x has higher priority than the concatenation operator . . However, this is not all that happens here, and the problem itself arises from a poor solution.

First of all, when you say

 print (($foo . "\n") x $count); 

What you do is change the context of the repeat statement for the list context.

 (LIST) x $count 

The above statement really means this (if $count == 3 ):

 print ( $foo . "\n", $foo . "\n", $foo . "\n" ); # list with 3 elements 

From perldoc perlop :

The binary "x" is the repeat operator. In a scalar context, or if the left operand is not enclosed in parentheses, it returns a string consisting of the left operand repeating the number of times indicated by the right operand. In the context of a list , if the left operand is enclosed in parentheses or is a list formed by qw / STRING / , it repeats the list . If the right operand is zero or negative, it returns an empty string or empty list, depending on the context.

The solution works as intended because print accepts list arguments. However, if you have something else that takes scalar arguments, such as a subroutine:

 foo(("text" . "\n") x 3); sub foo { # @_ is now the list ("text\n", "text\n", "text\n"); my ($string) = @_; # error enters here # $string is now "text\n" } 

This is a subtle difference that may not always give the desired result.

The best solution for this particular case is to not use the concatenation operator at all, since it is redundant:

 print "$foo\n" x $count; 

Or even use more mundane methods:

 for (0 .. $count) { print "$foo\n"; } 

or

 use feature 'say' ... say $foo for 0 .. $count; 
+3
source

All Articles