[e-lang] Proposal: The "where" expression

Mark S. Miller markm at cs.jhu.edu
Tue May 29 00:27:11 EDT 2007


I had a perverse idea of a simple lightweight syntax for doing remote 
evaluation of E code: The where-expression. The appeal of this syntax is that 
it is so similar to the simple case of the existing when-expression, both 
syntactically and semantically, so that it provides much power for a very low 
incremental learning cost.

In the simple when-expression:

     def p2 := when (p1) -> { ... p1 ... }

the expression in the block to the right of the "->" is postponed until p1 is 
fulfilled. Only after p1 is fulfilled, this block will execute in its own 
separate turn (top-level transaction). The when-expression immediately returns 
a promise for the value that this block will evaluate to. All this is brought 
about first by packaging up the block on the right into a call-back object.

The proposed where-expression:

     def p2 := where (p1) -> { ... p1 ... }

instead packages up the block on the right into a PassByCopy call-back object 
and passes it as the argument of a __whenMoreResolved message sent to p1. 
Therefore, this block is expected to execute only after p1 is fulfilled, but 
is expected to execute in a separate turn *in the vat* hosting the object p1 
designates. In the when-expression, the expression on the right may safely 
assume p1 is fulfilled (i.e., near or far). In the where-expression, the 
expression on the right may safely assume p1 is near.

In both cases, p2 is immediately bound to a promise for what the expression on 
the right will evaluate to. In the where-expression, this is generally a 
remote promise.

Given this syntax, a pleasant way to spawn a vat for purely computational 
purposes is to spawn it containing a pass-by-proxy mascot object that does 
nothing, but serves to represent its hosting vat. Then, one could spawn 
computation into that vat with the intuitive

     def p2 := where (vatAMascot) -> { ...expr to evaluate in vat A... }

                      Expansion


A proposed expansion (after a bit of trivial simplification for readability):

    (def [p2,r2] := Ref.promise()
     (p1) <- __whenMoreResolved(
         def _ implements PassByCopy {
             to run(p1) {
                 try {
                     r2.resolve(... p1 ...)
                 } catch ex {
                     r2.smash(ex)
                 }
             }
             to __optUncall() {
                 return [eval,
                         "run",
                         [meta.context().getSource(),
                          meta.getEnv()]]
             }
         })
     p2)

This presumes a working PassByCopy auditor, though the existing pbc 
(pass-by-construction) auditor should be good enough to get started. In also 
presumes a pervasive eval/2 function which can recreate a PassByCopy object 
from its reflectively obtained AST and lexical environment. We are very close 
to being able to support this, mostly pending the precise specification of 
what such a lexical environment contains.



             Security

As stated, the above proposal has a hidden security hazard. From all the rest 
of E, a programmer looking at

     def p2 := where (p1) -> { ... p1 ... x ... }

would be right to expect that p1 can only cause x to be manipulated in ways 
that the expression above manipulates it. However, by passing the closure by 
copy to p1's vat, we're also giving p1's vat (whom we might not trust) direct 
access to x. I'm not sure what to do about this. Perhaps we should insist that 
the block refer freely only to safe things and p1?

-- 
Text by me above is hereby placed in the public domain

     Cheers,
     --MarkM


More information about the e-lang mailing list