The below code defines a List type and two implementation of case classes one representing empty list and Cons to create actual list
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
...
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
val example = Cons(1, Cons(2, Cons(3, Nil)))
}
is my assumption correct that the list is created by the recursive apply method above when the val example = ...
is executed.
if that is so. the signature for creating Cons is Cons(head, tail)
where as the signature of the apply is incompatible variad
def apply[A](as: A*): List[A]
, how does scala actually infers the val example
to be List(1, 2, 3, Nil)
When you say
class Foo(s: String, i: Int)
in scala, it generates a class Foo
with a constructor taking a String
and an Int
.
It's pretty much the same as a java class declared as
public class Foo {
public Foo(String s, int i) {
...
}
}
With case classes, the compiler provides extra-goodies such as a companion object with a default apply
method taking the same parameters as the constructor.
So that's why you can directly call Cons(head, tail)
, without explicitly define a constructor.