You can do it if you explicitly declare your self-referential val
as Lazy
:
sealed class MyData {
data class A(val x: Int) : MyData()
data class B(val x : Int, val rb: Lazy<MyData>) : MyData() {
val r: MyData by rb
}
}
fun <A : Any> rec(body: (Lazy<A>) -> A): A {
lateinit var a: A
a = body(lazy { a })
return a
}
fun MyData.print(gas: Int): String = if (gas <= 0) "..." else
when(this) {
is MyData.A -> "A(x=$x)"
is MyData.B -> {
val rbString =
if (rb.isInitialized())
r.print(gas - 1)
else
"<thunk>"
"B(x=$x, rb=$rbString)"
}
}
fun main() {
val a = MyData.A(42)
val b1 = MyData.B(1, lazy { a })
println(b1.r) // Force value
println(b1)
val b2 = rec<MyData.B> { b2 -> MyData.B(1, b2) }
println(b2.r.print(4))
}
This prints
A(x=42)
B(x=1, rb=A(x=42))
B(x=1, rb=B(x=1, rb=B(x=1, rb=B(x=1, rb=...))))