0

Hi I'm learning Scala recently and I am confused about the null/nothing in Scala, in the following code, I'm implementing a customer linked list with generic type, and practice with variance

Defined my abstract class

 /** * head = first element of the list * tail = remainder of the list * isEmpty = is this list empty * add(int) => new list with this element added * toString => a string representation of the list */ abstract class MyList[+T] { val head: T val tail: MyList[T] val isEmpty: Boolean def add[A >: T](n: A): MyList[A] def printElements: String override def toString: String = s"[$printElements]" } 

Two types of node class - Empty and Cons

class Empty[+T] extends MyList[T] { override val head: T = ??? // what should I implement at here??? override val tail: MyList[T] = null override val isEmpty: Boolean = true override def add[A >: T](elem: A): MyList[A] = new Cons(elem, this) override def printElements: String = "" } class Cons[+T](h: T, t: MyList[T]) extends MyList[T] { override val head: T = h override val tail: MyList[T] = t override val isEmpty: Boolean = false override def add[A >: T](elem: A): MyList[A] = new Cons(elem, this) override def printElements: String = { if (tail.isEmpty) s"$head" else s"$head, ${tail.printElements}" } } 

Here is my test

object ListTest2 extends App { val listOfIntegers: MyList[Int] = new Cons(1, new Cons(2, new Empty[Int])) val listOfString: MyList[String] = new Cons("1", new Cons("2", new Empty[String])) println(listOfIntegers) println(listOfString) } 

I tried to define an object Empty for the last node in this linked list.

//object Empty extends MyList[Nothing] { // override val head: Nothing = throw new NoSuchElementException // override val tail: MyList[Nothing] = null // override val isEmpty: Boolean = true // // override def add[B >: Nothing](elem: B): MyList[B] = new Cons(elem, Empty) // override def printElements: String = "" //} 

But it run with exception during the initiation.

2

1 Answer 1

3

Returning null from tail is not so good idea. This can lead to NPE. It's better to fail early, so just throw (if this is your semantics of the method). Better semantics is to return an empty list.

head also can throw. This is the only way to create a value of arbitrary type T. If you can change the signature then it's better to return Option[T] i.e. None instead of null or exception.

Normally, in a trait or abstract class, abstract members (head, tail, isEmpty) should be def. Whether they are actually def, val or lazy val is implementation details (and should be specified in inheritors).

I tried to define an object Empty for the last node in this linked list... But it run with exception during the initiation.

You can avoid exception if you make head a lazy val (or def)

override lazy val head: Nothing = throw new NoSuchElementException 

def can be overridden with def, val, lazy val.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.