[e-lang] Object coercion / adaptation

Mark S. Miller e-lang@mail.eros-os.org
Sun, 05 May 2002 14:53:32 -0700


At 02:08 PM 5/3/2002 Friday, Ka-Ping Yee wrote:
>> "getOptMeta" is rather horrible, but "conform" has too narrow a meaning --
>> getOptMeta is for a general purpose dispatch on a brand, modeled on Joule's
>> Energetic Secrets protocol.  It can be used for much else besides type
>> conformance. However, I'd dearly like to get rid of the name "getOptMeta".
>[out of order]
>Or, put another way: as far as i can tell, the current contract to which
>getOptMeta commits is "given a brand, return whatever".  That's too vague
>for me; i'd prefer a more specific contract like "given a guard, return
>a representative for yourself that conforms to it".

In general, I *VERY STRONGLY* agree with the design heuristic you present 
above.  getOptMeta (or whatever we rename it to) is our second exception to 
this heuristic.  To understand why this exception is a good idea, let's 
start with our first exception: method dispatch.

E objects are closures.  Closures are functions-with-state, and a 
conventional function simply has parameters.  Conventional functions don't 
have a built-in notion of method dispatch.

Seen from this perspective, E's plumbing expression 
http://www.erights.org/elang/blocks/defPlumbing.html is properly seen as 
more primitive that E's normal object definition expression.  The plumbing 
expression defines an object as a simple function, and a call to an object is 
an application of this function to the message as the unitary argument.  
Except for Miranda Methods, E's object expressions could be seen as 
syntactic sugar for use of the plumbing expression.  Our old friend the point

    def point {
        to getX() :any {x}
        to getY() :any {y}
        to add(other) :any { ... }
    }

is nearly equivalent to

    pragma enable("plumbing")

    def point match msg {
        switch msg {
            match [`getX`, []] { x }
            match [`getY`, []] { y }
            match [`add`, [other]] { ... }
        }
    }

and indeed, method dispatch is defined by such expansions in 
(chronologically) Smalltalk-72, Actors, T, and Joule.  An object is just a 
function of a message.  (Or rather, a function-with-state.)

Such objects-as-functions, when described at the function level of 
abstraction, violate your design heuristic in exactly the same fashion -- 
they "do whatever they do", depending on the meaning of the message they are 
applied to.  But everyone is happy to make this exception, because method 
dispatch is needed in order to create the world in which your heuristic 
applies -- a world in which distinct methods are used for distinct tasks.
So long as the above mechanism is adequate *as* a method dispatch mechanism, 
we don't need to make any further exceptions.

The security properties of the above method dispatch mechanism corresponds 
directly to capability security as normally practiced, such as by KeyKOS and 
EROS.  The message name (or order code) is guessable data, and the message 
itself is a transparent data structure, such that any intermediary 
forwarding the message can play man-in-the-middle.  This 
transparency-by-default is essential for pervasive virtualizability.

T was the first language to explore a method dispatch mechanism with 
stronger security properties.  In T, the role normally played by "message 
name" or "order code" is instead played by a first class anonymous selfish 
object.  I don't remember what this was called, so I'll call it the 
"dispatch object".  The use of a message name in the caller's environment is 
looked up in the caller's lexical scope in order to find the dispatch object 
to be used in the message.  The use of a method name in the callee's 
environment was looked up in the callee's lexical scope to find the dispatch 
object used to index the callee's dispatch table.  The same dispatch object 
might be known by different names to different callers, and by yet different 
names to different potential callees, but as long as they are all talking 
about the same dispatch object it all works.

Besides more flexible name-space management, this mechanism also provides T 
with some interesting security properties.  Specifically, if Alice doesn't 
have access to the dispatch object normally named "Point_getX", then she 
can't get the X coordinate of any point.  However, since, in T, the message 
structure is still transparent, if she virtualizes a point (plays MITM) 
which she can pass to someone who wants the point's X coordinate, she can 
steal the dispatch object normally named "getX", and so obtain the X 
coordinate of all points she has access to.  So this scheme has properties 
stronger than normal capability practice, but the extra security is weaker 
than an oo equivalent of single key cryptography.

Inspired by this, Joule's Energetic Secrets mechanism
ftp://ftp.webcom.com/pub1/agorics/postscript/MANUAL.B17.ps.Z 
provides similar first-class-ness of dispatch objects, but the extra 
security is an oo equivalent of public key cryptography, implicitly using 
Sealer/Unsealer pairs as part of the message dispatch mechanism.  Using E 
terminology, the message being passed is a SealedBox whose Brand is the 
dispatch object.  The callee uses this Brand to look up a corresponding 
Unsealer, which was lexically bound by the callee's use of a method name.  If 
the callee finds such an Unsealer, it uses it to unseal the message and 
obtain the arguments.  Joule has no implicit continuations, so any response 
to the caller would only be sent along these arguments, and therefore only 
could be sent if these arguments could be obtained.  There's more to it than 
that, some of which is very clever, but that's the relevant part for the 
current story.

In E, for a variety of reasons (ask if your curious), I reverted to the 
simple capability story for the normal message sending case.  I see 
getOptMeta as a method only in the same way I see an E object as a function. 
An E object-as-function is the gateway to our first (conventional) method 
dispatch mechanism.  getOptMeta, found through this mechanism, is the 
gateway to our second (Energetic-Secrets-like) method dispatch mechanism.  

In a system like E, when functions are generally objects, essentially all 
functions should assume that their argument is a message, and complain about 
not understanding a particular kind of message, rather than becoming 
confused by treating it as something else. This is one way to explain what 
is meant by "everything is an object" http://www.paulgraham.com/reesoo.html .
In a similar though weaker vein, in a system where some objects implement 
a protocol for a second level of dispatch with different security 
properties, it's good to have universal support for invoking that second 
level, and for a callee to complain that it didn't recognize a Brand (a 
second level complaint) rather than complain that it didn't recognize 
getOptMeta/1 (a first level complaint).

E's getOptMeta mechanism is security-equivalent to Joule's Energetic 
Secrets, but as a method dispatch mechanism it is substantially harder to 
use.  However, for conformance, which is expected to remain by far the 
common case, it is easier to use than an adaptation of Energetic Secrets 
would be.  (In E, since the continuation isn't included in the message, is 
implicit, and isn't first class, it's not obvious what such an adaptation 
would look like anyway.)

[out of order]
>I see that general purpose dispatch on a brand is that *mechanism*
>currently used to implement getOptMeta, and that mechanism could be used
>to implement other things, but i'd rather not mix these different
>purposes just because they have similar mechanisms.  

Does the above adequately answer this?

>Also, as long as
>it's a Miranda method, getOptMeta can't really be used for general purpose
>anything, since its implementation is internal.  (I know it can be
>overridden, but the part that has to do with dispatching on a brand
>is internal, and E code cannot manipulate that dispatch table -- in fact
>we currently rely on the fact that it cannot.)

As far as I can tell, all user-defined behavior that we should support can 
be defined by wrapping (ie, virtualizing, MITM) the Miranda getOptMeta.  
Such virtualization can't violate its built-in security properties, but 
also, AFAI can see, doesn't prevent any pattern we should allow.  In 
particular, a user defined getOptMeta can do its own dispatch on the brand.


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

        Cheers,
        --MarkM