[e-lang] E patches for review: ELoader, seedVat

Kevin Reid kpreid at switchb.org
Fri May 21 04:25:11 PDT 2010


On May 21, 2010, at 4:59, Thomas Leonard wrote:

>> 1. Envs also have the distinction which prohibits binding a noun  
>> twice
>> within a single scope, and is controlled by nestOuter(). This is data
>> a ConstMap does not have.
>
> Is this useful when calling eval() from E?

The intent is that it should be possible to write an evaluator using  
Env (Scope) as the environment type. This is not possible if Env does  
not preserve this information.

>> 2. Once guard-based auditing is implemented, there will be an
>> additional indirection ('bindings'), besides slots, between env and
>> their values. The virtue of the distinct Env (Scope) type is that it
>> provides operations which allow clients to ignore these additional
>> features (slots and bindings) when they are not relevant to the
>> application.
>
> That's possible. I think it needs to be a separate type, though:
>
> - Scope: containing a ScopeLayout and an EvalContext with outers,  
> fields
> and locals) used internally.
>
> - Env / ConstMap: no layout, just "outers".

No. "Scope" is an incorrect and deprecated name. It is to be renamed  
to "Env". There is no distinction between them.

> But for simplicity I think I'd find it easier to understand if it was
> just a map from names to slots (or bindings), even if I had to write a
> little more code, e.g.
>
>  code.eval(safeEnv | [ "answer" => makeFinalSlot(42) ])
>
> I don't really like all the "if (k.startsWith("&"))" in Scope.java.

I don't either; I feel those interfaces should be deprecated. The  
solution I prefer is to have different methods for working with values  
vs. slots vs. bindings.

>> Thomas, would you be interested in working on implementing guard- 
>> based
>> auditing in E-on-Java? It would then be straightforward to add the
>> DeepFrozen auditor for E code to E-on-Java, which enables a variety  
>> of
>> useful possibilities.
>
> I'm a bit confused about DeepFrozen. For example, could this be
> DeepFrozen?
>
> def requireOne :DeepFrozen {
>    to run(x) {
>        require(x == 1)
>    }
> }

The correct syntax is

def requireOne implements DeepFrozen {
    to run(x) {
        require(x == 1)
    }
}

> It seems not, because it mutates &require:
>
> ? (&require).isFinal()
> # value: false
> ? requireOne(1)
> ? (&require).isFinal()
> # value: true
>
> Can any useful code be DeepFrozen?

This is a mistake in the implementation of safeEnv (safeScope), not in  
DeepFrozen. It should not be possible to observe whether a lazy eval  
slot has been forced yet, because otherwise it leaks information among  
users of a given safeEnv when it should not (regardless of the  
existence of DeepFrozen).


> I'm also confused about bindings. ... Is this so that auditors don't  
> get free access to all the values?

Yes. Auditors should be able to analyze the behavior of your code, but  
not use the authority it bears.

> If so, why not just subclass FinalSlot, e.g.
>
>  class AuditableFinalSlot extends FinalSlot implements AuditableSlot
>
> Then only give auditors auditable slots to look at (which would  
> include
> everything in safeScope)?

Because this would prevent auditing from working at all on custom  
slots unless they all carefully implemented AuditableSlot and were  
audited to do so correctly -- and what does 'correctly' mean for a  
sufficiently wacky slot? The binding system leaves it up to the  
auditor to determine what an acceptable slot is.

(On the other hand, the binding system does make some annoying  
complications, like &&foo, which are the part I like least about GBA  
as it stands now (which is entirely my own design); so if you could  
expand on this proposal and show it works better in practice, I'd be  
interested to hear it.)

>> Perhaps, instead of using the persistence sealer, use the unsafe
>> loader, which presumably can (ought to be able to, anyway) uncall
>> makeTraceln?
>
> It can, but I don't want to let people get makeTraceln from <this>,  
> e.g.
> with:
>
> def loader {
>    to __optUncall() {
>       return [makeLoader, "run", [sourceDir, envExtras, fqnPrefix]]
>   }
> }
>
> You could recover makeLoader with:
>
>  def makeLoader := <this>.__optUncall()[0]
>
> You can then use makeLoader to create loaders that log with any  
> fqname,
> or uncall it to get makeTraceln. So, I think this needs to be sealed
> somehow.

Hold on. I'm not sure how what I proposed makes a difference here.

Could you explain the entire object graph leading up to makeTraceln?

I suspect a violation of the principle that any object with private  
state must use an amplified uncall rather than __optUncall/0.

-- 
Kevin Reid                                  <http://switchb.org/kpreid/>






More information about the e-lang mailing list