mosceo
mosceo

Reputation: 1224

Precedence of the operators & and | in Scala

In the book "Programming in Scala" (Martin Odersky, 2nd edition) they give this operator precedence table (not complete here):

* / %
+ -
:
= !
< >
&
^
|

So that if the first character of an operator has a higher position in this table that the first character of another operator, the former operator is evaluated first.

According to that this code should print out yy, but it prints out x:

def x() = { print('x'); true }
def y() = { print('y'); true }

x || y && y        // prints `x` but should `yy`

My understanding is that if & is higher in the table that |, it must be evaluated first. It is like * has precedence over +, so in x + y * y, the last statement is evalueted first.


EDIT:

Also look at this code

def x() = { print('x'); 1 }
def y() = { print('y'); 3 }

x == x + y * y        // xxyy

Look like it evaluates them from left to right but "solves" them according to the table.

Upvotes: 0

Views: 1102

Answers (2)

rxg
rxg

Reputation: 3982

Raw version:

x || y && y

With precedence applied:

x || (y && y)

(Note, if the precedence was reversed it would be (x || y) && y.)

Now, you are expecting (y && y) to get evaluated before x, but Scala always evaluates left-to-right (see §6.6 of the language spec). And, as others have mentioned, || is a short-circuiting operator, so the the second operand is not even evaluated if the first operand returns true.

Another way to think of it is as a two method calls, where the second operand of both is pass-by-name:

or (x, and(y, y))

def or(a: Boolean, b: => Boolean): Boolean = if (a) true else b
def and(a: Boolean, b: => Boolean): Boolean = if (!a) false else b

Under the left-to-right evaluation model, x is ALWAYS evaluated first, then maybe y twice.

If you haven't already done so, you could follow Martin Odersky's functional programming course on Coursera where he talks about this very subject in lecture 1 or 2.

Your second example is equivalent to

add(x, mult(y, y))

def add(a: Int, b: Int) = a + b
def mult(a: Int, b: Int) = a * b

x is always evaluated first, then y, twice.

Upvotes: 3

4lex1v
4lex1v

Reputation: 21567

It prints x because x() call returns true and in case of || logic operator if left part return true, the right part is not computed. To compute it use | then, even if left part is true the right part will be evaluated

Updated

Example with boolean is not good, because in case with booleans so called "short-circuit" evaluation is used and scalac won't even look at the second part of or expression if the left part is true. Think of this operation like:

def || (a: => Boolean) = ???

Upvotes: 2

Related Questions