Scala :: lazy value is null unless printed?
Asked Answered
F

1

6

Given the trait (simplified)

trait A {
  val eventStream: EventStream
  val credentialsStorage = // something here
  val userStorage = // something here
  val crypto = // something here
  ...    
  lazy val authSvc = new CoreAuthentication(credentialsStorage, new AuthenticationProviderResolver, userStorage, eventStream, crypto)
}

class T extends A with TraitProvidingEventStream with FlatSpec with [lot of another traits here] {

  val eventStream = systemFromTraitProvidingEventStream.eventStream

  "This" should "work" in {
    println(authSvc) // this is "magic"
    val user = authSvc.doSomethingWithUser(...);
  }
}

if I remove line marked as //this is "magic", then I will get NullPointerException on the next line, so authSvc is null.

What may be wrong there?

I wasn't be able to create clean small test case for that, usually this works well

Feed answered 24/11, 2012 at 14:58 Comment(6)
Are you sure that the access to authSvc throws a NPE and not the method doSomethingWithUser or its parameters?Master
absolutely, even if it would throw NPE somewhere inside doSomethingWithUser - then println doesn't have anything to do about this.Feed
I'd like to debug this, but not sure how. Any help will be appreciated.Feed
I suspect this is something to do with the DelayedInit trait being mixed into your T class. You should try making the example truly minimal to see exactly where the bug is.Philemol
the thing is that I can not really narrow it down, it simply works as expected in all cases I tried but original source. So I would like to know how to debug that - may be it is some bug in scala compiler?Feed
What about toString() method of CoreAuthentication class? It gets called by println. Maybe it does something so that NPE doesn't occur?Mapp
E
5

This came up once on the ML: If an exception is thrown when initializing a lazy val, the val is null; but you can attempt to init again and it can work magically. (That is, the "initialized" bit flag for the lazy val is not set on the first failed attempt to initialize.)

I think the case on the ML had to do with init order of vals in traits, so maybe that's your problem. It's infamously dangerous to rely on it, hence the advice to use defs in traits. See Luigi's comment on DelayedInit.

Epigenesis answered 24/11, 2012 at 18:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.