The May 24, 2011 Scala Language Specification has a typo in section 6.12.3 as discovered here. This was acknowledged on the mailing list.
What is the actual precedence for the infix operators?
The logical-AND operator ( && ) has higher precedence than the logical-OR operator ( || ), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s-- .
For a long time, Scala has supported a useful “trick” called infix operator notation. If a method takes a single argument, you can call it without the period after the instance and without parentheses around the argument.
The precedence and meaning of some operators depends on the SQL mode: By default, || is a logical OR operator. With PIPES_AS_CONCAT enabled, || is string concatenation, with a precedence between ^ and the unary operators. By default, ! has a higher precedence than NOT .
In Scala, operators are methods. Any method with a single parameter can be used as an infix operator. For example, + can be called with dot-notation: Scala 2 and 3.
I thought it would be fun figuring it out by testing it, I wrote the following code to be executed in the REPL. Given:
val ops = List(
"letter", "|", "^",
"&", "<", ">", "!",
"+", "-", "*", "/", "%", "?",
"=?", // add ? to prevent assignment
":?" // add ? to prevent right-association
)
First generate an intermediate scala file that use and test the operators.
import java.io._
// generate a class with all ops operators defined
// where operator combines in a way we can figure out the precedence
val methods = ops.map("""def %s(o: Op) = Op("["+o.v+v+"]")""".format(_))
val body = methods.mkString("\n")
val out = new PrintWriter(new FileWriter("Op.scala"))
out.println("case class Op(v: String) {\n%s\n}".format(body))
// generate tests for all combinations and store in comps
// Op(".") op1 Op(".") op2 Op(".") v returns "[[..].]" when op2 > op1
// returns "[.[..]]" when op1 <= op2
def test(op1: String, op2:String) = {
"""("%s","%s") -> (Op(".") %s Op(".") %s Op(".")).v.startsWith("[[")""".
format(op1, op2, op1, op2)
}
val tests = for (op1 <- ops; op2 <- ops) yield { test(op1, op2) }
out.println("val comps = Map[(String, String), Boolean](%s)".format(
tests.mkString(",\n")))
out.close
Then Load Op class, run tests and load comps
:load Op.scala
// order operators based on tests
val order = ops.sortWith((x,y) => comps(x -> y))
// if op1 or op2 don't have higher precedence, they have the same precedence
def samePrecedence(op1: String, op2: String) =
!comps(op1 -> op2) && !comps(op2 -> op1)
def printPrecedenceGroups(list: List[String]): Unit = {
if (list != Nil) {
val (same, rest) = list.span(op => samePrecedence(op, list.head))
println(same.mkString(" "))
printPrecedenceGroups(rest)
}
}
printPrecedenceGroups(order)
This prints:
letter
|
^
&
! =?
< >
:?
+ -
* / %
?
So the main difference with the spec is < >
needs to be switched with = !
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With