10

The nearest thing to

case class Foo(lazy next: Foo)

that I have been able to come up with is

class Foo(_next: =>Foo) {
    lazy val next = _next
}
object Foo {
    def apply(next: =>Foo) = new Foo(next)
    def unapply(foo: Foo) = Some(foo.next)
}

I found a listed issue add lazy parameters so I guess it will be added someday. In the meantime, does anyone know a cleaner trick than the above?

Owen
  • 38,836
  • 14
  • 95
  • 125
  • It's worth mentioning that your `unapply` method isn't lazy, so trying to pattern match a `Foo` into another `Foo` will result in `next` being evaluated, which you may not want. – Brian McCutchon Sep 16 '17 at 05:18
  • @BrianMcCutchon That's a good point. I suppose the only way to make it lazy would be to add indirection, as in `def unapply(foo: Foo) = Some(() => foo.next)` ? – Owen Sep 16 '17 at 19:33
  • That seems to work. I was just avoiding using `unapply` for my lazy case classes. In that case, though, you need to explicitly call the function, like `case Foo(n) => Foo(doSomething(n()))`. At that point, it might be better to use `Need`. (Also, if you go the `Need` route, you can define an overloaded constructor for `Foo` that takes a call-by-name parameter and turns it into a `Need`.) – Brian McCutchon Sep 16 '17 at 19:45

1 Answers1

7

Maybe scalaz.Need? This was suggested to me in this answer.

scala> case class Foo(next: Name[Foo])
defined class Foo

scala> lazy val x: Foo = Foo(Need(y)); lazy val y: Foo = Foo(Need(x))
x: Foo = <lazy>
y: Foo = <lazy>

scala> x.next.flatMap(_.next).value eq x
res61: Boolean = true
Community
  • 1
  • 1
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • I suppose it is debatable whether this is cleaner. But the messiness is in a different place, so it is a useful alternative either way. – Owen Feb 07 '12 at 01:49
  • @Owen, that's the approach I have resorted to in past. I too would like to have first class language support. – missingfaktor Feb 07 '12 at 02:12