Infix operator associativity bug


#1

AFAIK infix operators should be left-associative unless they end with a colon. Apparently I have found a case where this is not true. First, consider the following example showing the expected behavior:

$ scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 9).
Type in expressions for evaluation. Or try :help.
scala> implicit class WithString(s: String) { def ~<(t: String) = s + t; def >~(t: String) = t + s }
defined class WithString

scala> "a" ~< "b" >~ "c"
res8: String = cab

scala> ("a" ~< "b") >~ "c"
res9: String = cab

scala> "a" ~< ("b" >~ "c")
res10: String = acb

Next, consider the following example showing the broken behavior:

scala> implicit class WithString(s: String) { def <~(t: String) = s + t; def ~>(t: String) = t + s }
defined class WithString

scala> "a" <~ "b" ~> "c"
res11: String = acb

scala> ("a" <~ "b") ~> "c"
res12: String = cab

scala> "a" <~ ("b" ~> "c")
res13: String = acb

Mind the slightly different infix operator names.

BTW: I get the thame behavior with Scala 2.11.11 on the latest Oracle JDK 8.


#2

I don’t think there’s any right-associativity here. It’s just the normal operator precedence rules at work, but the results look confusing because you prepend t to s. Correct me if I’m wrong.


#3

Obviously this is a contrived example, but the argument swapping is intentional. The infix operators are supposed to convey the intent of a direction. So my infix operators cannot be commutative, but they should be associative.

So only the first character of the infix operator is considered to determine the priority. For the second example, this is < and ~. According to the list of precedences on the linked page then, the infix operator ~> would always take precedence over <~, which matches the observed behavior.

To sum it up: This is not a bug, it’s a feature. Thanks for prodding my nose into the specs!


#4

Yes, I suggest always having a look at that list when designing some DSL so the precedence of your operators matches your expectations. Unfortunately that often means that you can’t use your preferred operator name.


#5

#6