Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MyList - step 3

Add method

  • Add the add method
  • Add the + method
  • Create a companion object

Exercise 1

trait MyList[A]:
  ...
  def add(element: A): MyList[A]
  • Give the MyList trait an add method
  • Implement it in Cons and Empty
  • And test it in main with: Empty().add(1).add(2).add(3)

Exercise 2

trait MyList[A]:
  ...
  def +(element: A): MyList[A]
  • Implement + operator as alias for add method
  • And test it in main with: Empty() + 1 + 2 + 3

Exercise 3

object MyList:
  def apply[A](elements: A*): MyList[A]
  • Implement the companion object
  • And test it in main with: MyList(1,2,3)

Add method

Empty

override def add(element: A): MyList[A] = Cons(element, this)

Adding an element to Empty means that Empty is not empty anymore and becomes a Cons with the tail Empty (this)

Cons

override def add(element: A): MyList[A] = Cons(element, this)

Adding an element to Cons means adding new head and the tail becomes the current Cons (this)

trait

trait MyList[A]:
  ...
  def add(element: A): MyList[A] = Cons(element, this)

The implementation in Empty and Cons are the same.
So we can move it up to the MyList trait (and remove them from Empty and Cons).
Via inheritance, they are available in Empty and Cons again

main

@main
def main(): Unit =
  val myList: MyList[Int] = Empty().add(1).add(2).add(3)
  println(myList)
  
//  MyList(3, 2, 1)

The order is reversed now.

Solution 2

trait MyList[A]:
  ...
  def add(element: A): MyList[A] = Cons(element, this)
  infix def + (element: A): MyList[A] = add(element)

In Scala + is a valid function name
With the infix modifier we do not have to use the braces in the function call.

@main
def main(): Unit =
  val myList: MyList[Int] = Empty() + 1 + 2 + 3
  println(myList)

//  MyList(3, 2, 1)

Solution 3

companion object

object MyList:
  def apply[A](elements: A*): MyList[A] =
    def build(elements: Seq[A], acc: MyList[A]): MyList[A] =
      if elements.isEmpty then acc
      else build(elements.tail, acc + elements.head)

    build(elements.reverse, Empty())

In the companion object we add the apply method with a varargs param list.
In a tail recursive build function we add the elements to MyList with our own infix +
Because the recursive call will build the MyList in reversed order, we start with reversing the elements

main

@main
def main(): Unit =
  val myList: MyList[Int] = MyList(1,2,3)
  println(myList)

//  MyList(1, 2, 3)