FW: Announcing E 0.8.3: A Candidate for a Usable Platform Tyler Close (tyler@waterken.com)
Wed, 21 Apr 1999 12:00:59 -0400

Maybe this will be a little easier to read.

Forwarded with permission.

Tyler

-----Original Message-----
From: Mark S. Miller [mailto:markm@caplet.com] Sent: Wednesday, April 21, 1999 2:13 AM
To: Tyler Close
Subject: Announcing E 0.8.3: A Candidate for a Usable Platform

E 0.8.3 is now released! As explained in the earlier http://eros.cis.upenn.edu/~majordomo/e-lang/0657.html this release is a candidate, coding-wise, for approximately what we'll be publicizing. In other words, I'm imagining that this version of the system is usable, useful, fun, and productive. I'm hoping it's not just a demo of the kind of distributed secure platform it will be when we have persistence, etc. Rather, that, as shown by echat, perhaps it is now an adequate platform for some real uses, including some distributed secure applications.

If anything BIG is missing besides adequate documentation, I'd love to find out now. So those who've been holding back, now would be a great time to give it a spin. Thanks.

In order to make it worth your while to start using it, you may need to know that the system is stable. In exchange for asking you to try actually using E, I need to commit that E will now only change in a way that's careful to keep as much old code working as reasonably possible. Non-upwards compatible changes will be resisted, but there will still be a few. When they do happen, it will be after discussion on the E list, and with documentation about how to cope with the changes.

Up to this point, it's been wonderful to have a community of heavy interest but light use, allowing me to make non-upwards compatible changes casually, simply because they made things better. Few systems get remotely as much breathing room as E has had to evolve in this way. This is the last release to make use of that freedom. These release notes will focus on these non-upward compatible changes, as well as all the grammar changes. I consider the current grammar a real candidate for the final grammar, to be extended from here only reluctantly, and only by utilizing currently reserved keywords.

What is the interface I'm committing to? Unfortunately, not yet the contents of the javadoc, but rather the documentation that will be in the tree rooted in "http://www.erights.org/elang/". Some of it's there but much of it isn't, and some of what's there is stale, so this commitment is currently somewhat hollow. I will now be trying to repair that as soon as I can.

So if you do pick E up and start using it, please let me know. If you have any impressions, please let me know. More important, if you stop using it, please tell me everything you can about why. Most important of all, if you do not try to start using E, please tell me what you can about why not, and what might make a difference. Thanks much.


Collection Classes and a Xanadu Surprise

The biggest piece of work was regularizing and completing the collection classes. A summary of the results are
"http://www.erights.org/elang/collect/tables.html". In doing this, I had been wrestling with the semantics of Interval objects, which were incoherent, when I got news that all the old Xanadu code and intellectual property had been open sourced. Yup, you heard that right. This isn't secret, but it's not ready to be publicized yet. What does this have to do with Intervals?

In the end, my favorite part of the Xanadu code came to be something we called "The Coordinate Space System". It was a simple theory of computable abstract geometry, or something like that, that will need to be explained well some other time. However, with these ideas available again, it was clear that E's Intervals were really just a special case of Xanadu's IntegerRegions -- which they now are. For E, the rest of Xanadu's coordinate spaces can wait till much later if ever, but 0.8.3 does incorporate OrderedRegions (IntegerRegions generalized to cover float64s and chars as well as integers). I know I'm not explaining them -- my apologies -- but I expect to be doing so in web pages.

AFAIK, these changes to collections added some new power, but are upwards compatible except for a few protocol changes and one semantic issue. The protocol changes:

list slice(2,7) -> list run(2,7)

Rather that referring to "slice"s of lists, we now refer to "run"s of lists, allowing us to employ the default message selector, "run", which may be left out, resulting in "list(2,7)". As applied to lists, let's call this "run notation".

	list slice(2) is now an error, instead
	                                  list run(2..!7)

The one argument form, rather than taking an integer start index, now takes an Interval, which seems more useful.

list replace(2,7,sublist) -> list setRun(2,7,sublist)

This, combined with an extension to the assignment transformations (see below) enable you to use the run notation on the left side of an assignment:

list(2,7) := sublist
expands to

list run(2,7) := sublist
expands to

list setRun(2,7,sublist); sublist

What's that last "sublist" doing there? It's to ensure that the value of the assignment expression is the value being assigned, as explained in assignment transformations below.

I'm using "&" and "|" for set intersection and union, which is consistent both with their logical meaning and with their use as bitwise operators on integers, for when you want to think of an integer as a bit-vector as a (pascal-like) set of natural (or is it whole?) numbers. I also use <, <=,
>=, and > (and now |=|, see below) for subset comparisons. However, one
operator gave me a headache: set subtraction. Not only isn't it subtraction, it conflicted with my desired use for "-" on IntegerRegions, and of course, it already means something different on integers. With great reluctance I introduce "&!", where "x &! y" means everything in x but not in y. If "!y" is defined, "x &! y" always means the same as "x & !y", but for explicit sets (EMaps used as sets), "!y" is an error. That's why "&!" needs to be a single operation.

The non-upwards compatible semantic issue is that the old Intervals represented both a set of contained integers and an enumeration direction. It would be bad to overload the new/old OrderedRegions with a direction, since they want to represent no more than which positions they contain. Therefore they always iterate (when they can) ascending. However, you can ask them for a separate object to iterate these positions in descending order. The one program broken by this is Ping's bottles-of-beer generator. Whereas before he could say:

for beer in 99..0 {

now he has to say

for beer in 0..99 descending {


Syntactic Changes

Alan Perlis said something like "With too much syntactic sugar, you'll get cancer of the semicolon." With this release, some of you will think E has stepped over that line, and it may have. But each of these changes at least addresses a real need, and the E Kernel language didn't change at all. It's at least only sugar.

Unary Prefix Precedence

In the other C like languages, the unary prefix operators "!", "~", and "-" bind less tight then the unary postfix operators, including "." as method call. For example, in Java

-x.foo()

would parse as "-(x.foo())".

On the principle of minimizing surprise, E simply followed that precedence order. However, with E's use of juxtaposition instead of ".", this doesn't work visually:

-x foo

Simply looks like it should parse as "(-x) foo". However, I couldn't swap the precedence on the principle that I can't accept a conventional C-like expression but parse it differently. As with other confusion vs compatibility conflicts, I can give a parse-time rejection surprise, but not a run-time behavior surprise. I have these not associate. E no longer accepts "-x foo". You have to say "(-x) foo" or "-(x foo)".

Assignment Transformations

Assignment expressions are supposed to evaluate to the value they're assigning. This property used to be awkwardly and incorrectly distributed among the things assignments call, but now it results purely from the expansion. For example, as a first approximation,

a[i] := v

expands to

a get(i) := v

expands to

a put(i, v); v

That last "; v" is new. The responsibility to return the assigned value used to be delegated to put(). Why "first approximation"? "v" may be an expression. If so, it should only be evaluated once and this value used twice. The actual transformation does this.

Similarly, the expansion of

a[i] += v

no longer expand to

a put(i, a get(i) + v)

since that evaluated "a" and "i" twice. Now it expands to

define t1 := a
define t2 := i
t1 put(t2, define t3 := t1 get(t2) + v) t3

Where the t<digit> variables would actually be temporary names made up by the parser in a way that's guaranteed not to conflict. Notice that this expansion preserves the textual (and therefore chronological and scoping) left to right order of the original.

Which calls on the left of an assignment are transformed the way get/1 ("get" of one argument) is turned into put/2 above? It used to only be that get/n was turned into put/n+1. Now, to accommodate Python-like run manipulation, run/n becomes setRun/n+1 enabling one to write

list(2,7) := newSubList

The JavaBeans property convention is all over the java libraries, and is pervasive in the UI libraries (both awt and swing). The convention defines a property by a pair of a get<Name>/n method and a set<Name>/n+1 method, where n is typically 0 but not always. <Name> is the name of the property transformed by toUpperCase on the first character. For example, in Java,

Fu getFoo(int i)

paired with

void setFoo(int i, Fu fu)

would define a property named "foo". I'm not sure why user interface code tends to be especially voluminous and tedious, but it does. If a small syntactic concession can make dealing with the existing UI libraries significantly more pleasant... And my bookstore market survey technique kept telling me Beans are Big. So I made two concessions. First, as you're probably already expecting, get<Name>/n on the left of an assignment gets transformed to set<Name>/n+1, so for example

b getFoo(i) := fu

is transformed into

b setFoo(i, fu)

This wraps up assignment, but not yet JavaBeans. Having liberated "." from method call, and with no field access in the language, I reallocated "." to property access:

b.foo
expands to

b getFoo
and

b.foo(i)
expands to

b getFoo(i)

This of course works with the previous transformation to yield

b.foo(i) := fu
expands to

b setFoo(i, fu)

I took the only piece of significant GUI code we've got, MarcS' echat, and partially transformed it to use this new syntax. It was a significantly more readable.

Coordinate Spaces

"_" was already a special piece of punctuation used by patterns to mean "match anything without binding". You could think of it as a generic variable definition, where that variable couldn't subsequently be named. It is now used on the expression side with a strangely analogous meaning:

2..!7

now expands to

(_ >= 2) & (_ < 7)

which expands to

(ForAllX >= 2) & (ForAllX < 7)

I won't bother showing the expansions for ">=", "<", and "&" since they haven't changed.

So syntactically, the new role for "_" isn't very special: it's just shorthand for "ForAllX", which is just a name in the standard environment, not a keyword. The object it names is written in E, and is the means by which other coordinate space objects will typically be constructed. But what does it mean?

(_ >= 2) means "All integers >= 2", or, more explicitly, "The IntegerRegion consisting of all integers >= 2". You can understand it first as a lightweight notation for lambda, sort of:

	define atLeast2(x) {
	    x >= 2
	}

And indeed, regions acts this way:

	? define reg := (_ >= 2)
	# value: (_ >= 2)

	? reg(3)
	# value: true

	? reg(1)
	# value: false

However, in general predicates have no knowledge of themselves. Regions do.

	? reg isEmpty
	# value: false


Finally, I had been resisting and resisting introducing an operator for the ordering-equality explained as "arithEqual" on "http://www.erights.org/elang/float64-ref.html", but the region notation issue pushed me over the edge. "x |=| y", now expands to "x compareTo(y) isZero". As a result, a singleton region of a coordinate space can now be expressed as "(_ |=| y)".

I realize much of this was explained badly, but at release time the main thing is a heads-up of all things different to be aware of. Now that I can more simply focus just on the documentation, I hope to have decent explanations available soon.

	Toward phase transition,
	--MarkM