61

In Scala, I can make a caseclass, case class Foo(x:Int), and then put it in a list like so:

List(Foo(42))

Now, nothing strange here. The following is strange to me. The operator :: is a function on a list, right? With any function with one argument in Scala, I can call it with infix notation. An example is 1 + 2 is a function (+) on the object Int. The class Foo I just defined does not have the :: operator, so how is the following possible?

Foo(40) :: List(Foo(2))

In Scala 2.8 RC1, I get the following output from the interactive prompt:

scala> case class Foo(x:Int)
defined class Foo

scala> Foo(40) :: List(Foo(2))
res2: List[Foo] = List(Foo(40), Foo(2))

I can go on and use it, but what is the explanation?

nbro
  • 15,395
  • 32
  • 113
  • 196
Felix
  • 8,385
  • 10
  • 40
  • 59

4 Answers4

56

From the Spec:

6.12.3 InfixOperations An infix operator can be an arbitrary identifier. Infix operators have precedence and associativity defined as follows.

...

The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left- associative.

You can always see how these rules are applied in Scala by printing the program after it has been through the 'typer' phase of the compiler:

scala -Xprint:typer -e "1 :: Nil"

val r: List[Int] = {
  <synthetic> val x$1: Int = 1;
  immutable.this.Nil.::[Int](x$1)
};
retronym
  • 54,768
  • 12
  • 155
  • 168
  • 1
    It also applies for passing type parameters to type constructors. Let say you have a case class ::[H, T](head : H, tail : T); and class SomeType[A]; then you could do both new SomeType[::[String, Int]]("a", 3) and new SomeType[H :: T]("a", 3) – lisak Aug 04 '14 at 13:45
24

It ends with a :. And that is the sign, that this function is defined in the class to the right (in List class here).

So, it's List(Foo(2)).::(Foo(40)), not Foo(40).::(List(Foo(2))) in your example.

George
  • 8,368
  • 12
  • 65
  • 106
  • 4
    In other words, `a ::::: b` (just to be silly) is the same as `b.:::::(a)`. Additionally, methods whose names end in colon and used in infix style associate to the right, rather than to the left, so `a :: b :: c` is the same as `c.::(b.::(a)))` – Randall Schulz May 13 '10 at 14:03
21

One aspect missing in the answers given is that to support :: in pattern matching expressions:

List(1,2) match {
  case x :: xs => println(x + " " + xs)
  case _ => println("")
}

A class :: is defined :

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) 

so case ::(x,xs) would produce the same result. The expression case x :: xs works because the default extractor :: is defined for the case class and it can be used infix.

Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
19

The class Foo I just defined does not have the :: operator, so how is the following possible:

Foo(40) :: List(Foo(2))

If the method name ends with a colon (:) the method is invoked on the right operand, which is the case here. If the method name doesn't end with colon, the method is invoked on the left operand. For example, a + b, + is invoked on a.

So, in your example, :: is a method on its right operand, which is a List.

nbro
  • 15,395
  • 32
  • 113
  • 196
Surya Suravarapu
  • 1,539
  • 1
  • 13
  • 12