Eugen Konkov
Eugen Konkov

Reputation: 25133

Please explain perl operator associativity

The DOC explains perl operator precedence and associativity. I am interesting at -> and * operators. Both have left associativity.

I have next example and it seems that -> has right associativity. Not left as documentation states:

my @args;
sub call { print "call\n"; shift @args }
sub test { print "test\n"; 1 }
sub t4 { print "t4\n"; 4 }

@args=( \&test, 2, 3 );
call()->( @args, t4 );


sub m1 { print "m1\n"; 2 }
sub m2 { print "m2\n"; 4 }

m1()*(@args, m2);

The output is:

t4
call
test
m1
m2

Because -> has left associativity I expect next output:

call
t4
test
m1
m2

What did I miss? Why t4 is called before call?

Upvotes: 1

Views: 171

Answers (3)

ikegami
ikegami

Reputation: 385819

You are asking about operand evaluation order (the order in which operands are evaluated), not operator associativity (the order in which operators of the same operator precedence are evaluated).

The operand evaluation order is undefined (or at least undocumented) for many operators, including ->. You will find it consistent, but one shouldn't rely on that.

You can use statement breaks to force the desired order:

my $sub = call();
$sub->( @args, t4 );

This would also work:

$_->( @args, t4 ) for call();

Operator Associativity

Associativity is the order in which operators of the same precedence are evaluated.

For example, * and / have the same precedence, so associativity determines that

 3 / 4 * 5 * 6

is equivalent to

 ( ( 3 / 4 ) * 5 ) * 6 = 22.5

and not

 3 / ( 4 * ( 5 * 6 ) ) = 0.025

As you can see, associativity can have a direct effect on the outcome of the expression.


Operand Evaluation Order

Operand evaluation order is the order in which operands are evaluated.

For example, operand evaluation order determines whether 1+2 is evaluated before 3+4, or vice-versa in

( 1 + 2 ) * ( 3 + 4 )

Unless evaluating the operand has a side-effect (e.g. changing a variable or printing to the screen), then operand evaluation order has no effect on the outcome of the expression. As such, some languages leave it undefined to allow for optimization.

In Perl, it's undefined (or at least undocumented) for many operators. It's only documented for the following:

  • The comma operator (, and =>): left to right
  • Binary boolean operators (and, or, &&, || and //): left, then maybe right[1]
  • Conditional operators (? :): left, then either second or third[1]
  • List and scalar assignment operators (=): right, then left[2]
  • Binding operators (=~ and !~): left, then right[3]

  1. Required for short-circuited evaluation.
  2. Required for my $x = $x;.
  3. Required to function at all.

Upvotes: 4

Dave Sherohman
Dave Sherohman

Reputation: 46187

Associativity describes the order that multiple operators of equal precedence are handled. It has nothing to do with whether the left arguments or the right arguments are processed first. -> being left associative means that a->b->c is processed as (a->b)->c, not as a->(b->c).

Upvotes: 2

user2404501
user2404501

Reputation:

Associativity is a rule that tells you how to parse an expression where the same operator appears twice, or more than one operator with the same precedence level appears. For example, associativity determines that:

foo()->bar()->baz()

is equivalent to

(foo()->bar())->baz() # left associative

and not

foo()->(bar()->baz()) # right associative

Since your code only hase one -> operator in it, the associativity of that operator is irrelevant.

You seem to be looking for a rule about the order of evaluation of operands to the -> operator. As far as I know, there is no guaranteed order of evaluation for most operators in perl (much like C). If the order matters, you should split the expression into multiple statements with an explicit temporary variable:

my $tmp = call();
$tmp->( @args, t4 );

Upvotes: 3

Related Questions