dickwall / activator-akka-scala-parfait

Example of Parfait Pattern for Dependency Injection with Akka
Other
7 stars 3 forks source link

passing value of object that hasn't been created yet would benefit from explanation #2

Open LogicalTime opened 8 years ago

LogicalTime commented 8 years ago

I'm coming from your class on parleys.com. In StandardAuditModuleTrait am confused about this line: lazy val auditCompanion: ActorRef = actorSystem.actorOf(AuditCompanion.props(this), AuditCompanion.name)

AuditCompanion.props takes a AuditModule. How are we passing in a reference to StandardAuditModule into a function to make it's own value that defines it? Could you either add guidance to this or a link to where we can get the guidance. Does one of your course flights cover this?.

dickwall commented 8 years ago

The reference to the standard audit module means that the AuditCompanion when it is constructed, so it knows where to go for the dependencies. This is why it is necessary to make the computed values in standard audit module lazy though, to avoid any potential initialization problems. By making the definition of AuditCompanion a lazy val (or def), its creation doesn't really happen until after the module has been completed, at which time the module can be passed in safely. General rule of thumb that makes this easy to remember is that in any trait or dependency module like this, any computed value (i.e. not just a constant literal but something that calls a method or constructor itself) should either be a def or a lazy val.

LogicalTime commented 8 years ago

Thanks for the response Dick! I think the thing that is driving me crazy is passing into the initialization of a lazy val an object that has that same lazy val as a member. If we invoke that lazy val during its own initialization (perhaps we want to log some members and haphazardly include that reference) we get a runtime stack overflow error. Just playing devils advocate, adding the println statement below gives such a stack overflow error:

object AuditCompanion {
  val name = "AuditCompanion"
  def props(implicit auditModule: AuditModule) = {
    println("haphazard logging mistake causes stack overflow:" + Option(auditModule.auditCompanion))
    Props(new AuditCompanion)
  }
}
dickwall commented 8 years ago

Right - this is the symptom - laziness only works if it is preserved, the first non-lazy val in the initialization causes the failure you see. It's important to realize though that this is also a problem in cake, but results in nulls (initialization not ready) rather than a stack overflow. Both are runtime errors and both need to be avoided with a lazy val definition. As I say, a non-lazy val in either traits or config modules that are anything other than a simple constant definition probably constitutes a bug. One of these days I will write an abide rule for that.

LogicalTime commented 8 years ago

I made a simple change that eliminates this issue and submitted a pull request. Eager to hear if I am approaching this right or if I am missing something crucial. :-)