sclass LazyVar implements IF0 {
  *() {}
  *(A *v) { if (v == null) calculating = new Var; }
  *(IF0 *f) {}
  
  IF0 f;
  
  // will keep var around after the fact (we could change this by counting how many threads are waiting)
  Var> calculating;
  A v;
  
  public A get() {
    bool meCalc;
    
    if (v != null) ret v;
    
    synchronized {
      meCalc = calculating == null;
      if (meCalc)
        calculating = new Var;
    }
    
    if (meCalc) {
      OKOrError b = okOrError(() -> f!);
      calculating.set(b);
      synchronized { ret v = b!; }
    } else {
      waitUntilNotNull(calculating);
      ret v;
    }
  }
  
  public synchronized bool isEvaluated() { ret f == null; }
  
  public synchronized bool has() { ret get() != null; }
  toString { ret isEvaluated() ? str(get()) : "LazyVar"; }
}