ERights Home elib / capability / horton 
Back to: Alice Frames Carol On to: Horton with Lexical Nesting

Eventual Horton


? pragma.syntax("0.9")

This version is like the basic simplified Horton, but modified to use only eventual-sends ("<-") and promises between principals, in order to avoid any additional liveness hazards between principals. In this version we use the otherwise-absent return path to indicate when we're done, for testing purposes.

? def c {
>     to hi(_) {
>         println("hi")
>     }
> }
# value: <c>
 
? c.hi(c)
# stdout: hi
#
 
? def b {
>     to foo(c_) {
>         return c_ <- hi(c_)
>     }
> }
# value: <b>
 
? interp.waitAtTop(b.foo(c))
# stdout: hi
#
 
? def makeA(b_, c_) {
>     def a {
>         to start() {
>             return b_ <- foo(c_)
>         }
>     }
>     return a
> }
# value: <makeA>
 
? def directA := makeA(b, c)
# value: <a>
 
? interp.waitAtTop(directA.start())
# stdout: hi
#

Note that makeProxy below has been modified to return a promise for the proxy. This promise is only resolved to the proxy once its stub instance variable is itself resolved, since, until then, the sender of a message to the proxy doesn't yet know that whoBlame should actually be held responsible for servicing these messages.

Most places in the original where we were passing a Who around, since these are now possibly-eventual references, we are instead passing around (by copy when remote) a pair of a Who and a String name for logging. As with the base version, the logged names are not yet securely interpretable designators. This security issue is repaired later when we introduce petnames.

# E sample
 
def makeQuoteln := <elang:interp.makeQuoteln>
 
def makeProxy([whoBlame_, nameBlame :String], stub_, reportln) {
    return when (stub_) -> {
        def log := makeQuoteln(reportln,
                               `I ask $nameBlame to:`,
                               75)
        def proxy {
            # as P2
            to getGuts() {
                return [stub_, [whoBlame_, nameBlame]]
            }
            # as P1
            match [verb, [p2]] {
                log(`$verb/1`)
                def [s2_, [whoCarol_, nameCarol :String]] := p2.getGuts()
                def gs3_ := s2_ <- intro([whoBlame_, nameBlame])
                def p3Desc := [gs3_, [whoCarol_, nameCarol]]
                stub_ <- deliver(verb, [p3Desc])
            }
        }
    }
}
 
# as S2
def wrap(s3_, whoBob_, beCarol) {
    def provide(resolverBox) {
        def resolver_ := beCarol.unseal(resolverBox)
        resolver_ <- resolve(s3_)
    }
    return whoBob_ <- seal(provide)
}
 
# as S1
def unwrap(gs3_, whoCarol_, beBob) {
    def provide_ := when (gs3_) -> { beBob.unseal(gs3_) }
    def [result, resolver] := Ref.promise()
    def resolverBox := whoCarol_ <- seal(resolver)
    provide_ <- run(resolverBox)
    return result
}
 
def makeStub(beMe, [whoBlame_, nameBlame :String], targ, reportln) {
    def log := makeQuoteln(reportln,
                           `$nameBlame asks me to:`,
                           75)
    def stub {
        # as S2
        to intro([whoBob_, nameBob :String]) {
            log(`meet $nameBob`)
            def s3_ := makeStub(beMe, [whoBob_, nameBob], targ, reportln)
            return wrap(s3_, whoBob_, beMe)
        }
        # as S1
        to deliver(verb, [p3Desc]) {
            log(`$verb/1`)
            def [gs3_, [whoCarol_, nameCarol :String]] := p3Desc
            def s3_ := unwrap(gs3_, whoCarol_, beMe)
            def p3_ := makeProxy([whoCarol_, nameCarol], s3_, reportln)
            return E.call(targ, verb, [p3_])
        }
    }
    return stub
}

The makePrincipal code is changed only to add the names to blame, since all other needed changes were already in the code above.

# E sample
 
def makeBrand := <elib:sealing.makeBrand>
 
def makePrincipal(label :String) {
    def reportln := makeQuoteln(println, `$label said:`, 77)
    def [whoMe, beMe] := makeBrand(label)
    def principal {
        to __printOn(out :TextWriter) {
            out.print(label)
        }
        to who() {
            return whoMe
        }
        to encodeFor(targ, [whoBlame, nameBlame :String]) {
            def stub := makeStub(beMe, [whoBlame, nameBlame], targ, reportln)
            return wrap(stub, whoBlame, beMe)}
        to decodeFrom(gift, [whoBlame, nameBlame :String]) {
            def stub := unwrap(gift, whoBlame, beMe)
            return makeProxy([whoBlame, nameBlame], stub, reportln)
        }
    }
    return principal
}

The players:

? def alice := makePrincipal("Alice")
# value: Alice
 
? def bob := makePrincipal("Bob")
# value: Bob
 
? def carol := makePrincipal("Carol")
# value: Carol

Initial connectiivity:

? def gs1 := bob.encodeFor(b, [alice.who(), "Alice"])
 
? def gs2 := carol.encodeFor(c, [alice.who(), "Alice"])
 
? def p1  := alice.decodeFrom(gs1, [bob.who(), "Bob"])
? def p2  := alice.decodeFrom(gs2, [carol.who(), "Carol"])
? def a := makeA(p1, p2)

The resulting transcript is identical to the previous, although it now takes place over multiple turns.

? interp.waitAtTop(a.start())
# stdout: Alice said:
#         > I ask Bob to:
#         > > foo/1
#         Carol said:
#         > Alice asks me to:
#         > > meet Bob
#         Bob said:
#         > Alice asks me to:
#         > > foo/1
#         Bob said:
#         > I ask Carol to:
#         > > hi/1
#         Carol said:
#         > Bob asks me to:
#         > > meet Carol
#         Carol said:
#         > Bob asks me to:
#         > > hi/1
#         hi
#
 
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home elib / capability / horton 
Back to: Alice Frames Carol On to: Horton with Lexical Nesting
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign