Why do we need Nil when creating a List in scala?

I have one main question in List

I get the error below when I tried to create a List with cons statement

scala> val someList = 1::2 <console>:10: error: value :: is not a member of Int val someList = 1::2 ^ 

But if you look below, as soon as I add Nil at the end, it will work.

  scala> val someList = 1::2::Nil someList: List[Int] = List(1, 2) 

I would like to know why Nil is required at least once at the end when we create the list

Is Nil a data type? or empty item?

+8
list scala
source share
4 answers

Exactly because of this reason.

value :: is not a member of Int

In Scala, operators are actually functions of objects. In this case, :: is a function of the Nil object, which is actually an empty list object.

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

When you execute 1::2 , Scala looks for a function named :: by 2 , and it does not find it. That is why it fails with this error.


Note: In Scala, if the last character of the operator is not a colon, then the operator is called on the first operand. For example, 1 + 2 is basically 1.+(2) . But, if the last character is a colon, the operator is called on the right side of the operand. So, in this case 1 :: Nil is actually Nil.::(1) . Since :: returns another list object, you can link it like this, for example, 1 :: 2 :: Nil , Nil.::(2).::(1) .

+9
source share

Infix statements whose names end with : are interpreted as method calls in the right operand. So, 1 :: 2 is 2.::(1) , that is, it calls the :: method on 2 . Similarly, 1 :: 2 :: Nil is Nil.::(2).::(1) .

The reason the first one does not work is because 2 is Int and Int does not have a :: method. The reason the second one works is because Nil is a list, and lists have a :: method. And since the result of List.:: also a list, you can still call :: as a result of the first :: .

+4
source share

Nil is the main building block for creating a List as a recursive data structure. The list is a useful data structure that provides O (1) time access to the head (first element).

List on it the minimal core built on 3 operations of head , tail and isEmpty . Nil is a single-class subclass of the List class, so it is a special instance of its type, representing an empty list . The cons :: operator is defined in List to build a list recursively by adding one element to the list.

See definition of List attribute and Nil object (very simplified)

 trait List[A] { def head: A def tail: List[A] def isEmpty: Boolean } case object Nil extends List[Nothing] { def head = throw new NoSuchElementException("head of empty list") def tail = throw new UnsupportedOperationException("tail of empty list") def isEmpty = true } 

Since any identifier / operator that ends with : is bound to the right, the :: operator is also bound to the right.

When you write 1::2::3 , scala tries to rewrite these calls as 3.::(2.::(1)) . those. 3 becomes the receiver of the first :: call, which does not exist on any arbitrary data type (Int in this case).

That's why you always build up on an empty list - Nil. Think of it as adding each item one by one to an empty Nil list.

+2
source share

The right operand defines any operator from Scala ending with a colon : So, when you write 1::2 , then :: should be defined on 2 ie on Int , which is not so.

Nil is a List value and has on it a method defined by :: . Therefore, when you write 1 :: 2 :: Nil , it is rated as (Nil.::(2)).::(1) .

+1
source share

All Articles