REPL output while creating empty list

scala> val empty = List()
empty: List[Nothing] = List()

scala> val empty = Nil
empty: scala.collection.immutable.Nil.type = List()

First output tells that empty is of type ‘List[Nothing]’.

Second output tells that empty is of type ‘scala.collection.immutable.Nil.type’. What does this one mean?

It means that Nil is a specialised object implemented as an optimisation for the specific case of an empty list. Nil is what you get when you call a method like List.empty.

Calling List() is the same as a call to List.apply(Array.empty). You still get an empty list; a generic one that works fine but it’s not optimised specifically for being empty.

It means that Nil.type is a subtype of List[Nothing].

My understanding is that REPL output has format:
name of the variable: type of the variable = value of the variable
So first output is in line with this.

But, second output has type as ‘scala.collection.immutable.Nil.type’. Nil is singleton in Scala. So Nil.type causes confusion to me.

Singletons totally have types, just like everything else.

Think of it this way: a “type” says more or less “what objects are allowed to be contained here”. From that viewpoint, Nil.type means “the type that can contain the object Nil, and nothing else”. It’s still a type – just a really small one…

1 Like

Most of the times a type can be said to be a noun, like List[Nothing] . Nil.type doesn’t seem to fit that.
May be I am not able to express myself correctly here.

Perhaps the source of the confusion is that you are used to the type of an instance being the class that it was created from. That is how things work in general with class-based OO languages. However, an object isn’t instantiated from a class. In addition, the name of the object is not used as the type name the way it is for classes. (If it were, you would have problems with companion objects.)

What is why the type of Nil isn’t just Nil. So now the question is, why is it Nil.type? It turns out that this isn’t a special case for singleton objects. Consider the following totally pointless bit of Scala REPL.

scala> class Foo(a: Int)
defined class Foo

scala> val f = new Foo(5)
f: Foo = Foo@2fd954f

scala> val v: f.type = f
v: f.type = Foo@2fd954f

Notice that last line? Instances of classes also have specific types. Literally, every instance has its own type in the type system. This is possible because f.type is a subtype of Foo.

The following blog post from last year goes into a lot more detail about the types in Scala, and it might help illuminate some things.

https://typelevel.org/blog/2017/02/13/more-types-than-classes.html

2 Likes

So f is of type Foo,while f.type is a subtype of Foo.

Actually, the most specific type of f is f.type, which is a subtype of Foo. The type of the expression new Foo(5) is Foo, which is why the REPL printed in out that way.

As the blog post makes very clear at the beginning, every value in Scala has many types. They start by showing 5 types for "greeting", and they left out Any. It then shows that there are other types that aren’t classes.

1 Like

To correct what was said earlier, an empty List is always the object Nil. Moreover, the compiler will optimize List() to Nil, knowing what must come of it, and avoid the method call.