The story of E, part 2 (fwd)

Mark S. Miller markm@caplet.com
Tue, 13 Oct 1998 14:29:22 -0700


I am currently unable to keep up with the list traffic in real time, while
answering in the depth that I want.  At the same time, many small issues go
by, like "length" vs "size" vs "count", for which I'm happy to propose a
decision quickly to see if we've got a quick settlement, or to raise
further implied questions that might get quickly settled.

This reduces the ambiguity of the background against which the big issues
need to be addressed.  So I'll try to clear out the backlog of easy
resolutions in real-time, but come back to the biggies (like concurrency,
and our old unresolved equality discussion) as soon as I reasonably can.
Sorry, but this latter will often not be real time.


At 03:27 AM 10/11/98 -0700, Ka-Ping Yee wrote:
>Why are MappingImpl and tupleMaker differently capitalized and
>why does MappingImpl not end in "Maker"?

Currently, a stupid reason:  Because MappingImpl is a Java class and
tupleMaker should itself be written in E.  I agree this needs to be fixed.
This raises a nasty style question -- which is better:

a)	define Point(x, y) {
	    define self {
	        to getX {x}
	        to getY {y}
	    }
	}
	define pt := Point(3, 5)
or
b)	define PointMaker(x, y) {
	    define point {
	        to getX {x}
	        to getY {y}
	    }
	}
	define pt := PointMaker(3, 5)
or
c)	define PointMaker make(x, y) {
	    define point {
	        to getX {x}
	        to getY {y}
	    }
	}
	define pt := PointMaker make(3, 5)
or
d)	define PointMaker new(x, y) {
	    define point {
	        to getX {x}
	        to getY {y}
	    }
	}
	define pt := PointMaker new(3, 5)
?

A Java class really consists of two things, which in E are turned into two
objects:  1) The Java class object, as described in java.lang.Class and
augmented by org.erights.e.meta.java.lang.ClassSugar, will be made to act
as an E type.  2) The public constructors and static members declared in a
class declaration.  These are made to appear (by virtue of
org.erights.e.elib.prim.EStaticWrapper) in E as instance methods of an
object that corresponds to the class.  The Java convention is to name a
class as a descriptive of its instances.  So what name should we associate
with each of the parts of a Java class?  Currently, the expression

	load:java.lang.Object

is a URI expression that (given that uriGetters["load"] is bound to an
appropriate ClassLoader) loads the object whose instance methods correspond
java.lang.Object's public constructors and static members.  Therefore the
following sequence works:

	define Object := load:java.lang.Object # like an import statement
	...
	define unique := Object new

If you want the class object corresponding to this class, currently you'd say:

	Object instanceType

If we go with any of the PointMaker conventions above (all but #a, but
especially with #d), then I propose that 

	load:java.lang.Object

load the class object, but that a class object be sugared with a "maker"
method to get its corresponding EStaticWrapper.  The following sequence
would then work, and be normal style:

	define Object := load:java.lang.Object #gets the *type*
	define ObjectMaker := Object maker
	...
	define unique := ObjectMaker new

If we adopt this, then we'd naturally use "Point" to name the type that
describes the protocol spoken by objects made by the above PointMakers.


>What is the complete list of globally-available helper objects?

Currently, the big-bang environment is (from the source for a slightly
future version of org.erights.e.elang.syntax.ScopeSetup)

        Object[][] parentPairs = {
            { "true",           Boolean.TRUE },
            { "false",          Boolean.FALSE },
            { "null",           null },

            { "makeTuple",      TupleMaker.theOne() },
            { "Promise",        new EStaticWrapper(Promise.class) },
            { "MappingImpl",    new EStaticWrapper(MappingImpl.class) },
            { "EQMatcher",      new EStaticWrapper(EQMatcher.class) },

            { "help",           new Help() },
            { "uriGetters",     uriGetters },
            { "quasiParsers",   quasiParsers },

            { "settable",       ???/*makes a SettableSlot*/ },
            { "final",          ???/*makes a FinalSlot*/ },
            { "defineSlot",     ???/*returns the specimen as the Slot*/ },

            { "stdout",         stdout },
            { "print",          new PrintFunc(stdout) },
            { "println",        new PrintlnFunc(stdout) },
            { "interp",         interp }
        };

where the quasiParsers are a scope initialized with

        Object[][] quasiPairs = {
            { "simple",         new EStaticWrapper(Substituter.class) },
            { "e",              new EStaticWrapper(EParser.class) }
        };

and the uriGetters are a scope initialized with

        Object[][] uriPairs = {
            { "load",           loaderScope },
            { "cap",            ???/*dereferences SturdyRefs*/ }
            { "file",           new FileGetter() },
            { "fileURL",        new URLGetter("file") },
            { "http",           new URLGetter("http") },
            { "ftp",            new URLGetter("ftp") },
            { "gopher",         new URLGetter("gopher") },
            { "news",           new URLGetter("news") },
            { "mailto",         new URLGetter("mailto") },
        };


This list needs to be reconciled with Chip's
org.erights.e.boot.EEnvironment, which is ELib's answer to a big-bang
environment.

Note: I am *NOT* attached to most of these names.  Feel free to suggest
good ones.

"Big-bang environment" is a KeyKOS term for the set of capabilities
provided to the first primordial user-object when generating a system.
This user-object executes with the full authority of the machine owner.  It
then initializes the world, handing out subsets of this authority to
components according to the principle of least authority.  See
http://erights.org/doc/to-be-sorted/EBoot.html and
http://erights.org/doc/to-be-sorted/ECDAFStart.html  (Are there good KeyKOS
or EROS pointers?)

I propose that the following subset of the above environment represents
*no* authority, and so can be assumed to be universal:

        Object[][] parentPairs = {
            { "true",           Boolean.TRUE },
            { "false",          Boolean.FALSE },
            { "null",           null },

            { "makeTuple",      TupleMaker.theOne() },
            { "Promise",        new EStaticWrapper(Promise.class) },
            { "MappingImpl",    new EStaticWrapper(MappingImpl.class) },
            { "EQMatcher",      new EStaticWrapper(EQMatcher.class) },

            { "help",           new Help() },
            { "uriGetters",     uriGetters },
            { "quasiParsers",   quasiParsers },

            { "settable",       ???/*makes a SettableSlot*/ },
            { "final",          ???/*makes a FinalSlot*/ },
            { "defineSlot",     ???/*returns the specimen as the Slot*/ }
        };

Same quasi-parsers as above.

The only binding in uriGetters is "load", and it's bound to a java
ClassLoader that only loads a known to be non-authority-granting subset of
the standard java classes.  I might be argued out of including "load" at all.


>Can you screw up a program by replacing these objects?

These variables are "final", so you cannot assign to them -- ie, the
primordial scope binds these to FinalSlots, and FinalSlots do not support
"setValue", ie, they do not support ":=".

However, you can shadow them in an inner scope.  At the same time, various
syntactic expansions expand to contain references to these.  What happens
if such a syntactic form appears in a scope where one of these is shadowed?
 There are two schools:

C and ancient Lisps: expand first, then do scope analysis.  In this school
you get the shadowed meaning.

Scheme & imitators reply: "What about *lexical* don't you understand?"

The idea of lexical scoping is that you should be able to match definition
and use by textual containment in the source code as written and read by
programmers.  From this point of view, the previous position is making an
static aliasing mistake similar to that made dynamically in pre-Scheme
Lisps.  If you statically apply the lexical-scoping paradigm, you get
"hygienic macros", about which there are many papers.

Even though, on the one hand, the E macro rules make hygienic expansion
substantially easier than with Scheme (since you can do scope analysis
before expansion), I doubt E can be completely hygienic, about which more
in some other message.


>What about the issue of how you print out mutable mappings and tuples?
>I still think some sort of distinctive punctuation could make a good
>way to indicate mutability.  Or were you planning to print out, e.g.
>"[1,4,5] newMutable" for a mutable tuple?  That seems kind of clunky.

Modulo the choice of name, it doesn't seem clunky to me.  Besides, mutable
structures are insufficiently virtuous to warrant special syntax ;)


>Would you consider "freeze" and "thaw"?

I like the direction, and would certainly be amenable to such a pair.  But
not this one, as it is often used for serializing/unserializing an object
graph.


>... I would like you to consider the sugar
>methods "getslice" and "putslice" -- they make a nice parallel
>to "get" and "put", and if expanded from [x:y] notation in the
>language grammar would be really useful.

First of all, in E, "x:y" expands to

	uriGetters["x"]["y"]

>> 	? list[list size -1]
>> 	# value: 7
>
>I use the negative indices quite often; they're pretty handy.

Ok, negative indices are in.


>> Nothing like [Python's slice assignment] in E.  Do you find it a great 
>> convenience?  Do you actually use it?
>
>Yes, i do use it, though admittedly not extremely often.  When
>i do use it i am quite thankful for it.
>
>I just like Python's slice notation a lot because it can express
>a lot of list-manipulation ideas -- append, insert, slice, delete,
>replace -- with one consistent orthogonal notation.  Perl tries
>to subsume many of these under "splice", but quite clumsily so.

Might it be illuminating to tell us about Perl's "splice"?


>Because Python's slices don't complain on out-of-bounds indices,
>they make it really convenient for me to just check things without
>getting paranoid about catching exceptions:
>
>   if word[:1] == "a":    # does this (possibly empty) word start with 'a'?

I don't get it.  What does "word[:1]" evaluate to if "word" is empty?  For
such cases, I believe thrown exception are your friend.  They catch more
bugs earlier, by making many expressions implicitly do the job of
assertions:  To my eye, the above program is telling me that it knows that,
at that point in the computation, "word" must be non-empty.  Execution will
only proceed beyond that point of that is actually true.  Such pervasive
subliminal assertions make programming less error-prone.

I could still be argued out of allowing negative indices on the above grounds.


>> Ask me about Ropes sometime.
>
>Okay.  What are Ropes?

There's a wonderful PARC blue&white:

Ropes Are Better Than Strings 
Hans-J. Boehm, Russ Atkinson, and Michael Plass 
September 1994 

I tried to find an online version but failed.  (Guess what you find when
you web-search on "ropes"?)  A Rope is shallow, heuristically-balanced
binary tree that represents an immutable sequence.  A lot of the operations
you'd think you'd need mutability for, like your proposed slice-assignment,
can be done efficiently in a semantically side-effect free fashion using
Ropes.  They build a text editor whose contents at any moment is an
immutable sequence of characters.  Each edit operation derives a new
sequence from the old one (with plenty of subtree-sharing and other tricks).

I'd like E's Strings and Tuples to eventually be Ropes.  So, if there was a
syntactically nice way to ask "give me a new Tuple like this Tuple but in
which this subrange is replaced by this Tuple", would you still want the
side effecty version?


>Any particular motivation that made you go with get/put
>instead of get/set?  No objection here, only curiosity.

java.util.Dictionary & java.util.Hashtable.  Beans, though, argue in the
other direction.


	Cheers,
	--MarkM