1

here is my code:

    val l1 = List(1,2,3)
    val l2 = List(4,5,6)
    val l1l2_1 = l1 ::: l2
    val l1l2_2 = l1.:::(l2)
    val l1l2_3 = l2.:::(l1)
    println(s"l1 = $l1 \nl2 = $l2 \nl1 ::: l2  = $l1l2_1 \nl1.:::(l2) = $l1l2_2 \nl2.:::(l1) = $l1l2_3 }")

and here is output:

l1 = List(1, 2, 3) 
l2 = List(4, 5, 6) 
l1 ::: l2  = List(1, 2, 3, 4, 5, 6) 
l1.:::(l2) = List(4, 5, 6, 1, 2, 3) 
l2.:::(l1) = List(1, 2, 3, 4, 5, 6) }

Why l1 ::: l2 is not equal with l1.:::(l2)?

user1726919
  • 83
  • 1
  • 6

2 Answers2

4

Operators that end in : are treated differently from other ones. When used with infix notation, they reverse their arguments - the method is invoked on the argument on the right and the argument on the left is used as the parameter. So l1 ::: l2 is the same as l2.:::(l1).

wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
  • Good to know...but that's insane. Principle of least surprise, indeed. – acjay May 22 '14 at 05:14
  • Not that insane. Every language has precedence and associativity roles! You have to deal with it. – tabdulradi May 22 '14 at 07:41
  • @acjay to be fair, this aspect mentioned in every introductory Scala book – om-nom-nom May 22 '14 at 11:39
  • @om-nom-nom To be fair, not everyone reads an introductory book before coding, and not everyone who does permanently retains every arbitrary corner case. Presuming a person falls into this class, the result is surprising programming errors, not resulting from a faulty mental model of the syntax, but from edge cases in the semantics that cannot possibly be anticipated. Don't get me wrong, I really like Scala, but I think that's a design smell. – acjay May 22 '14 at 12:35
  • @acjay I cannot believe that you wanna this operator working in opposite way, that would be insane. – panurg Aug 11 '15 at 13:59
  • @panurg Why would that be insane? You could simply make lists Nil-first. Instead of `head` being the first item, we could just think of lists as being last-in, first-out and have `end` be the most accessible item instead. As far as I can tell, the generality would be the same, but without having to understand some operators working backward. What would be lost? In any case, if associativity is variable, it seems there's got to be a more sensible way to annotate that than reserving a single character for the purpose. – acjay Aug 11 '15 at 18:08
1

Reason is two rules in Scala:
1. : operator/method is right associative.
2. Operator/Methods associativity is determined by the last character in the operator name.

For example:
Any method with arbitrary name, but ending with a :

def myMethod:(a: Any)

is treated like a :, so x myMethod: y is right associative too, and executed like y.myMethod:(x)

Read more in Programming in Scala book: Basic Types and Operations

tabdulradi
  • 7,456
  • 1
  • 22
  • 32