Proposal: Squeak-E = Squeak x Kernel-E

Mark S. Miller markm at caplet.com
Tue Jan 28 18:20:04 UTC 2003


I'm just coming out of a crunched schedule, sorry, and promise to catch up 
on this thread and post replies over the next couple of days. But I do have 
a moment...


At 12:36 AM 1/28/2003 Tuesday, cg at cdegroot.com wrote:
>5. is probably even less useful, where the compiler determines scope.
>
>Mark, if you're still with us, could you answer my questions two clicks
>up this thread or otherwise inform us on scoping of names in E? 

Strictly absolutely only lexical scoping according to lexical nesting, just 
as Scheme without fluid variables.

Scheme's fluid variables are much like Common Lisp's dynamic variables -- 
both are dynamically scoped. Fluid variables are a bit better from a 
capability perspective, but not better enough. When designing Joule 
http://www.agorics.com/Library/joule.html , E's most important and direct 
ancestor, Dean and I both thought we had a few cases that justified 
genuinely justified dynamic scoping. Although, as I recall it took Norm 
months to pry our fingers loose from this idea, he did prod us to go through 
each of these cases and see that the lexically-scoped answer was simply 
better on all dimensions we cared about -- security, convenience, 
understandability -- then the dynamically scoped answer.

Some of these better answers involved Joule's Type Extension feature, which 
is very similar to Anthony's Class Extensions. Joule's Type Extensions, like 
the selectors of Jonathan Rees' T language which preceded it, was itself a 
purely lexically-scoped notion. In order to solve these problems in a 
similar manner, Anthony's Class Extensions will need to be made lexically 
scoped as well. Fortunately, I think is should be straightforward.

E currently has no such extension feature, and we have not missed it yet, 
but we may eventually. I think I can mostly postpone that bridge until it 
burns me.

All the remaining interesting issues have to do with the outermost lexical 
scope. E code appears in two contexts:

Privileged: 
    command-line / Elmer (like a Squeak top-level Workspace)
    *.e files, (conceptually like a Java or C main(). 
                  Not clear if there's a sensible Smalltalk analogy.)

Confined:
    *.emaker files, *.caplet files (modules. Moral equivalent of Smalltalk classes)
    All mobile code (eg, in support of PassByCopy objects)

Most all E code exists in a Confined context. The outer scope of this 
context is known as the "safeScope" (though it was known as the 
"universalScope" when the Darpa security review analyzed it at: 
http://www.combex.com/papers/darpa-review/security-review.html#UniversalScope ).
The key thing is that this scope is immutable, contains only transitively 
immutable objects, and contains nothing that would enable an object to 
affect or be affected by the world outside itself. (ie, no "authority")

emakers can import other emakers, but since the other emakers are likewise 
authority-less, the safety is transitively upheld.


All E code in a privileged context represents the "top level" of a user 
request. Such code executes in a fresh "privilegedScope", which is mutable, 
and contains binds for objects that convey all the user's authority. All 
such code is therefore part of the user's TCB -- the user's interests are 
fully vulnerable to the misbehavior of such code. Ideally, this privileged 
code should do nothing but import those emakers that represent the logic of 
this app (or whatever), subdivide the user's authority, and call these 
emakers with least authority obtained from the user's authority.

<file:/foo/bar> is syntactic sugar for file__uriGetter.get("/foo/bar") .
The privilegedScope contains a binding from "file__uriGetter" to an object 
that conveys all the user's authority over the file system. The safeScope 
contains no such binding, so <file:/foo/bar> would normally be a static 
error in an emaker file.

The pattern that results from these constraints is that the outer level of 
an emaker typically defines an "author" (short for authorizer) that receives 
parameters representing the authority this emaker's logic needs to do it's 
duties. It then normally simply defines other objects in the scope of these 
authorization parameters, and returns one of them. A silly example:

    def zippyAuthor(file__uriGetter) :near {
        def zippy(name :String) :near {
            <file:/foo/bar>[name]
        }
    }

Note that, above, an emaker is able to say <file:..> because a variable 
named file__uriGetter is in scope.


This could be used from a privileged context as follows:

    def zippy := <import:com.combex.zippyAuthor>(file__uriGetter)

The programmer who wrote the above line should ask: Is file__uriGetter 
within zippyAuthor's least authority? In other words, is it really necessary 
for the job zippyAuthor is supposed to do? Further, do I trust zippyAuthor 
with this much authority. If the answer to the first is yes and the second 
is no, then you don't trust zippyAuthor to do its job and should probably 
not use it. 

    ...
    def file := zippy("snorgle")

Note that POLA discipline also provides virtualizability. The argument 
provided to zippyAuthor will be used by zippy as its file__uriGetter, but it 
need not be *the* file__uriGetter.



Because a Smalltalk image is a self contained persistent universe, I think 
some of the KeyKOS & EROS approaches to these startup issues may be more 
appropriate, and would prove safer than the patterns being used in E. But I 
haven't really thought about it.


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

        Cheers,
        --MarkM



More information about the Squeak-dev mailing list