Search code examples
scalacircular-list

What's the neatest way to define circular lists with Scala?


Here is my attempt:

case class A(val a: A, val b: Int){
    override def toString() = b.toString
}

lazy val x: A = A(y, 0)
lazy val y: A = A(z, 1)
lazy val z: A = A(x, 2)

The problem comes when trying to do anything with x; causing x to be evaluated starts off a circular evaluation going through x, y, z and ends in a stack overflow. Is there a way of specifying that val a should be computed lazily?


Solution

  • You need to make A.a itself lazy. You can do it by turning it into a by name parameter that is used to initialize a lazy field:

    class A(a0: => A, val b: Int){
      lazy val a = a0
      override def toString() = b.toString
    }
    object A {
      def apply( a0: => A, b: Int ) = new A( a0, b )
    }
    

    You could also do the same using a helper class Lazy:

    implicit class Lazy[T]( getValue: => T ) extends Proxy {
      def apply(): T = value
      lazy val value = getValue
      def self = value
    }
    

    It has the advantage that you code is pretty much unchanged except for changing a: A into a: Lazy[A]:

    case class A(val a: Lazy[A], val b: Int){
     override def toString() = b.toString
    }
    

    Note that to access the actual value wrapped in Lazy, you can either use apply or value (as in x.a() or x.a.value)