datnt
datnt

Reputation: 374

Please help to explain a case of Scala constructor and companion object

I think that I would make some mistakes in below explanation for my question but within my limit understanding I cannot figure out how to correctly describe the issue

The scala code snipet as below:

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: _*))
}

If I create object x as: val x = List(1,2,3)

I pass into companion object "List", three numbers as : 1 ,2 and 3 Then, internally, function apply is triggered At the moment of construction, how could these three numbers has method/attribute like: as.head and as.tail

I guess it could be possibly a kind of pattern matching, but even that, I could not understand the magic that number "as" now has method/attribute for ".head" and ".tail"

enter image description here

Upvotes: 0

Views: 66

Answers (2)

jwvh
jwvh

Reputation: 51271

Try this in the REPL.

scala> def apply[A](as :A*) = as
apply: [A](as: A*)Seq[A]

So the compiler considers the varargs variable, as, to be of type Seq[A], which is where the .head and .tail comes from.

Upvotes: 1

rics
rics

Reputation: 5596

The trick is that as: A* is a variable argument what is converted to an array-like object, actually a WrappedArray$ofInt in your case. WrappedArray has head and tail methods.

You can extend your definition of List object to see A*'s class like this:

object List {
  def apply[A](as: A*):List[A] = {
    println(as.getClass)    
    if (as.isEmpty) Nil
    else Cons(as.head, apply(as.tail: _*))
  }
}

For a more detailed explanation check e.g. this .

Upvotes: 0

Related Questions