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
|