How to check if a lazy val is initialized without initializing it?

You can do something like this:

object TheApp {

    private var _optionalSubsystemInitialized = false

    def optionalSubsystemInitialized = _optionalSubsystemInitialized

    lazy val optionalSubsystem = {
        _optionalSubsystemInitialized = true
        subsystem
    }

}

Whether is it really appropriate to have such side effects in the initialization code of a lazy val is another question.


This isn't really an answer to your question, and I hate when people do this, but I'm going to do it anyway. I think the best response is: A lazy val isn't appropriate for this, so define a type that does support what you need.

You'll have to refer to the variable as optionalSubsystem() rather than optionalSubsystem, but that's A Good Thing, because with the design you want, obtaining that reference is an observably side-effecting procedure.

class Lazy[A](f: => A, private var option: Option[A] = None) {

  def apply(): A = option match {
    case Some(a) => a
    case None => val a = f; option = Some(a); a
  }

  def toOption: Option[A] = option

}

scala> val optionalSubsystem = new Lazy { "a" }
optionalSubsystem: Lazy[java.lang.String] = Lazy@1210267

scala> optionalSubsystem.toOption.isDefined
res1: Boolean = false

scala> optionalSubsystem()
res2: java.lang.String = a

scala> optionalSubsystem.toOption.isDefined
res12: Boolean = true

Edit - Here's another revision with some modifications thanks to Tomas Mikula:

import scala.language.implicitConversions

object Lazy {

  def lazily[A](f: => A): Lazy[A] = new Lazy(f)

  implicit def evalLazy[A](l: Lazy[A]): A = l()

}

class Lazy[A] private(f: => A) {

  private var option: Option[A] = None

  def apply(): A = option match {
    case Some(a) => a
    case None => val a = f; option = Some(a); a
  }

  def isEvaluated: Boolean = option.isDefined

}

This lets you write lazily { ... } instead of new Lazy { ... }, and optionalSubsystem instead of optionalSubsystem().

scala> import Lazy._
import Lazy._

scala> val optionalSubsystem = lazily { "a" }
optionalSubsystem: Lazy[String] = Lazy@3d0d54

scala> optionalSubsystem.isEvaluated
res0: Boolean = false

scala> optionalSubsystem: String
res1: String = a

scala> optionalSubsystem.isEvaluated
res2: Boolean = true

Tags:

Scala