[Grace-core] Lazy initialisation and circular definitions

James Noble kjx at ecs.vuw.ac.nz
Wed Nov 19 01:33:35 PST 2014


Scala and Eiffel have support for lazy initialisation.

Eiffel has "once" routines that look like parameterless methods, but that are only called once
and that cache the return value. 

Scala has "lazy vals" that look like constant definitions, but where they are initialised when first
accessed and again cache the value of their initialiser.

Newspeak (above 0.08) has simultaneous slot declarations that bind the slot to a "promise"
(a proxy for its initialiser). These promises are forced when all slots are bound, so simultaneous
slots can be recursive, but the laziness does not persist after the object's construction. 

Idris has "mutual" declarations - I think these are somewhat similar.

Marco Servetto's placeholders (ECOOP 2013) are similar to Newspeak's design, except placeholders 
are opaque until they are all resolved (and include types to prevent errors) while Newspeak's proxies
allow calls between simultaneous slots provided they are well founded.  Racket's "shared"
is roughly similar to placeholders but rather more complex (http://docs.racket-lang.org/reference/shared.html).



These facilities can be used to support some recursive definitions, as well as 
lazy initialisation more generally.  How could we support this in Grace?

some options:

- basically nick the Eiffel design: have as special kind of "def" called a "once"  
     this adds a whole new declaration for something that won't be used very often

- nick the Scala design so we could write a "lazy" annotation. 

         def x : Number is lazy = y + z 

      this is a bit slightly lexically complex than Scala for the same power. 
      but this annotation seems to change the semantics of the language;
      We don't yet have a metamodel for annotations, but supporting this would 
      require a model where all initialisers were nominally packed into closures
      before annotations were processed.

- implement explicit "virtual proxies" that would take a block, and evaluate it on first access
      and either transparently forward (delegate) all requests, or transparently replace themselves 
  
         def x : Number = lazy { y + z } 

       this doesn't need an annotation, or to change semantics, although the syntax is a bit nastier overall. T
       If we had "does not understand" and delegation we could implement this reflexively.
       To me it seems a bit less "built in" than the other approaches, and "lazy" can be used in 
       more general computations as a delay with an implicit force. 

- implement some kind of placeholder/ simultaneous/ shared/ mutual definitions as a separate
     scoped declaration construct  

As an idea about how complex this can all get, see e.g. 
notes on implementing Scala's lazy val.  Another reason
to keep this out of the language core, perhaps?

http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html


'


More information about the Grace-core mailing list