Reputation: 519
I have a complex set of traits and case classes, but for the sake of the discussion let me summarize what I'm trying to model in this way:
case class X(x: X)
That's fine until I end up initializing one of the instances this way:
val myX: X = X(myX)
It compiles (unbelievably), but the myX
passed to the constructor is actually null, easily visible by checking myX.x
afterwards.
Suppose having an instance pointing to itself is fine for what I'm trying to model, is there an elegant way to solve this issue and have the new instance of X
with a pointer to itself? I mean without mutating the object after its creation, nor introducing a 2nd constructor that takes no parameter and uses this
inside. Remember please the real situation is more complex that what sketched here.
Upvotes: 0
Views: 96
Reputation: 15086
If you need to have a case class, I don't think it can be done. Case classes cannot have lazy parameters, and if they could point to themselves most of their methods would probably blow the stack. With a regular class you can do this:
scala> class X(x0: =>X) {
| lazy val x = x0
| }
class X
scala> val x: X = new X(x)
val x: X = X@5f98cb6f
scala> x.x
val res0: X = X@5f98cb6f
scala> x.x.x
val res1: X = X@5f98cb6f
If you want case class-like behavior you'll have to implement the boilerplate (apply, unapply, copy, equals, hashcode, ...) yourself, and be very careful not to trigger an infinite loop or a stack overflow.
Upvotes: 6
Reputation: 48400
Ill-advisedly, consider "simulating" by-name parameters in case classes like so
case class X(v: () => X) {
def x: X = v.apply
}
val myX: X = X(() => myX)
however note the warning by Jasper-M.
Upvotes: 2