5

First I declare a class:

class Op(var x : Int) {
  def +++(op: Op) = {
    println(this.x + " +++ " + op.x)
    this.x += op.x
    this
  } 
  def ***(op: Op) = {
    println(this.x + " *** " + op.x)
    this.x *= op.x
    this
  }
}

Now I execute the expression in REPL:

op1 +++ op2 +++ op3 *** op4

and it outputs

enter image description here

But why doesn't the method *** go first? Isn't the priority of *** higher than +++? And how about Java and C? Is it the same as in Scala?

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
爱国者
  • 4,298
  • 9
  • 47
  • 66
  • Why whould the priority of `***` be higher than `+++`? Just because it vaguely looks like multiplication and addition? – Jesper Nov 25 '11 at 15:16
  • 2
    No. The priority of method in scala is determine by the first character of the method name. For more information, please refer on section 8 of chapter 5 – 爱国者 Nov 25 '11 at 15:56

2 Answers2

13
op1 +++ op2 +++ op3 *** op4

is equivalent to

((op1 +++ op2) +++ (op3 *** op4))

since method calls are left-associative. Thus first (op1 +++ op2) is evaluated, since it's the first operand to the second +++. Then the second operand, (op3 *** op4) is evaluated. And finally, the outermost operator is evaluated.

The same would be true for op1 + op2 + op3 * op4 in C or Java.

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
5

Simple Rules

There are two rules that determine the order of op1 +++ op2 +++ op3 *** op4 expression evaluation:

Firstly since an operator starting with * takes precedence over an operator starting with + the expression is transformed into:

op1 +++ op2 +++ (op3 *** op4)

Secondly since there are multiple operators of the same precedence that appear side by side (op1 +++ op2 +++ ...) they are grouped left to right:

(op1 +++ op2) +++ (op3 *** op4)

Example

Consider the following expression:

op1 +++ op2 +++ op3 +++ op4 *** op5

Following the same two simple rules it will be evaluated as:

((op1 +++ op2) +++ op3) +++ (op4 *** op5)

Another Example

Alternatively let's apply the same two rules to op1 +++ op2 +++ op3 +++ op4 *** op5 *** op6:

Operators starting with * have precedence over operators starting with +:

op1 +++ op2 +++ op3 +++ (op4 *** op5 *** op6)

Then group operators with the same precedence left to right:

((op1 +++ op2) +++ op3) +++ ((op4 *** op5) *** op6)

Mutable Objects: a Word of Caution

The grouping makes perfect mathematical sense provided the +++ and *** methods do not have any side effects. Consider:

op1 +++ op2 +++ op1 *** op2

Intuitively the expression should return an object holding 5. However, because of the unfortunate side effects that +++ and *** methods produce in the original code sample (both modify the value stored within the object) the expression will result in an object holding 12 instead of expected 5.

That's why it's best to rely exclusively on immutable objects when constructing such expressions:

case class Op ( x: Int) {
  def +++(that: Op) = {
    println(this.x + " +++ " + that.x)
    Op(this.x+that.x)
  } 
  def ***(that: Op) = {
    println(this.x + " *** " + that.x)
    Op(this.x * that.x)
  }  
}

The Op(1) +++ Op(2) +++ Op(1) *** Op(2) expression will result in Op(5), as expected.

Vlad Gudim
  • 23,397
  • 16
  • 69
  • 92