The E Language Specification

Additional functionality for Java keywords. In E, you use regular
Java statements such as implements and imports. Generally,
the behavior of these keywords is the same as in Java.

The import statement has some additional functionality when
used in E, in that it also imports the sealers (as well as the related
classes and methods) for the messages in the E-classes and E-interfaces.

E reserved words

<- (send)

The send operator (<-), is the operator that sends E messages
to an E-object. The messageName and messageParameterList
take the same form as they do in a regular Java method call.

The recipientEobject denotes the E-object to which the message
should be sent. This can be an E-object proper or a channel. If you already
have a sealed message encapsulated in an envelope (that is, in an object
of class RtEnvelope), you can send it with an expression of the
form:

recipientEobject <- envelopeExpression;

where envelopeExpression is an expression whose result is the
envelope you wish to send.

Alternatively, the recipient can be a variable of class RtEnvelope.
In this case, the message is simply sealed in a new envelope which
is stored in the variable, but is not sent anywhere.

Examples

Send a message myMessage to an E-object called otherGuy.

otherGuy <- myMessage ();

The E-object otherGuy has a corresponding E-method called myMessage,
which it executes when it receives the message.

eclass otherGuyClassDefinition {
.......
myMessage();
.......
}

& (distributor operator)

& channelName

The distributor operator (the ampersand symbol) obtains a channel variable's
distributor (in order to send it a forward message, for example).
The result is of class EDistributor and you can treat it as a normal
value; for example, you can pass it as a message parameter.

You can only use this operator within the scope of the channel's initial
declaration. You cannot use this operator on a channel which has been passed
as the parameter of an E message or Java method call, or stored as an instance
variable of an object other than that object itself.

All variables whose class is EObject (or a subclass of EObject)
that have not been explicitly initialized in their declaration are implicitly
initialized to a new instance of EChannel. Such channels are initially
unforwarded (that is, they have not yet been given a destination E-object.
See the forward statement later in this chapter for more information).

To forward a channel, send the forward message to the channel's
associated distributor, including the destination E-object as a message
parameter (see the following example).

Example

&sparkPlug <- forward(spark);

This example extracts the distributor for the channel sparkPlug,
and sends the distributor a message forwarding it to spark.

eclass

The eclass statement defines a new E-class, and is similar
to Java's class statement.

An E-class can implement message protocols (called E-interfaces in this
manual) as well as regular Java interfaces. You designate an E-interface
with the einterface keyword. The optional interfaceList
is a comma-separated list of interface and E-interface names.

An E-class can only extend another E-class. If it is not explicitly
declared to extend another E-class, its immediate superclass is EObject.
E-classes inherit E-interfaces, E-methods, regular Java methods, and instance
variables from their superclasses.

Instance variables and Java methods in an E-class cannot be declared
public; they can only be accessed from within the object itself.
All references to the instance variables or Java methods of an E-class
must be made relative to this or super, either explicitly
or implicitly. This is because the reference may actually lead to a remote
E-object in a different machine across a network connection; its instance
variables and Java methods will not be directly accessible, even though
you can send E-messages to it.

An eclass body can contain any of the statements allowed inside
regular Java class body. In addition, it can contain either E-methods
or an eforall declaration. These are described in the following
subsections. Both Java methods and E-methods can use the E deferring statements
(such as ewhenandewhenever); these statements
are described later in this chapter.

An E-class can have either an eforall or an emethod
declaration; it cannot have both. However, it can still have Java methods
in either situation.

The modifiers are optional and can be either the public,
final or abstract Java modifiers.

Example

emethod

emethod methodName (parameterList) {
methodBody}

Theemethod declaration defines an E-method for an E-class.
An E-method is a block of code that is invoked when the E-object receives
a corresponding message with that E-method name. An E-class must have an
emethod declaration for each message it can receive. E-methods
and their corresponding messages are named within the scope of the containing
package (such as ec.e.run).

An E-method message parameter is typed in the same manner as a Java
method parameter. The parameterList consists of a series of comma-separated
entries of the form:

parameterType parameterName

The body of the E-method follows the same format as a Java method body.
Note that no return type is declared-since E-message sends are one-way,
there is no return value. Also, since E-methods are not "called"
by objects, they do not have access specifiers such as public
or protected.

Java classes cannot contain E-methods, though they can send messages
to E-objects.

Example

eforall

eforall (parameter
) {
methodBody
}

The eforall declaration is an alternative to an emethod
declaration. It receives all messages sent to instances of its class, but
it is given these messages in sealed envelopes which it cannot open, since
it lacks unsealers.

An eforall statement has a single parameter which must be of
class RtEnvelope; this parameter contains the sealed message. Although
the method cannot open the envelope, it can send it to other E-objects.
You can use this feature to implement message "plumbing" of various
sorts, such as forwarders, redirectors, and loggers.

Example

This example sends a message to an E-object newMiddleman containing
an eforall. The eforall logs the message and then sends
the sealed message on to another destination (theRealDestination)
without ever "opening" it.

eif

The eif statement is similar to the Java if statement,
and handles conditional execution clauses. However, it uses optimistic
computation to determine the condition. This condition must
be an EBoolean, though it can actually be a channel to an EBoolean
whose value is undetermined at the time the eif statement is initially
executed.

The eif statement is part of a special group of E statements
that defer code execution until a value is furnished for a variable. These
statements include eif, ewhen, ewhenever, and
the ecatch portion of etry. These statements are described
elsewhere in this chapter.

All other non-deferring statements in the code block which contains
the eif statement (including statements which follow the eif
in the source text), execute before the code blocks associated with the
eif, regardless of when the value of condition is furnished.

An eif statement defers execution of its associated code blocks
until condition furnishes a value. If there are no eorif
clauses (documented in the following subsection), and condition
is etrue, thenBlock executes. If condition is efalse,
the elseBlock executes (if there is one). If no EBoolean
is furnished for condition, neither block executes.

Using eif with Java code

An eif statement can only be used inside an E-class, although
it does not need to exist inside an E-method. Note, however, that if you
use eif inside a regular Java method, you cannot return a value
for that method from within the eif statement. This is because
the Java method will actually have returned before any of the blocks associated
with the eif gets executed. You can use a return
statement (without a return value) inside an eif to exit the eif
conditional block.

An eif statement can produce results different from Java's
if statement, even though the code may appear logically the same.
See the example at the end of this section for more information.

Multiway-guarded eif statement

If the eif statement contains one or more eorif clauses,
it becomes a multiway guarded eif statement. A multiway eif
handles conditional cases that are evaluated concurrently, such as timeouts.
This construct consists of an eif clause, followed by one or more
eorif clauses and an optional else clause:

The condition associated with thenBlock and the various
alternativeConditions associated with the eorifBlocks are
evaluated concurrently. The first to result in etrue has its associated
code block executed and prevents all the other code blocks from executing.
The elseBlock executes only if all the conditions result in efalse.

In a multiway-guarded eif, only one block will ever execute,
though none of them will if none of the conditions furnishes a value.

Examples

eif (Win) {
WinnerCode
} else {
LoserCode
}

In this example, WinnerCode executes if the value produced from
Win is true. LoserCode executes if the value is false.
Neither code block executes if there is no value.

Sample eif program

eif statements may produce results different from Java's if
statements, even though the code may appear logically the same. The following
code samples illustrate this idea.

The eorif guard clauses look for one of the following conditions
to be true: AlmostAtLight, StopLightRed, StopLightBroken,
StopLightYellow.

The first one that evaluates as true causes the appropriate code block
to execute: either SlowWayDown, StopSign, SpeedUp,
or Halt; the rest of the construct is then disregarded. If all the
guard conditions evaluate as false, code block ProceedAtSpeed executes.

einterface

The einterface statement encapsulates a set of abstract E-message
declarations, in the same way that Java's interface statement
encapsulates a set of abstract Java method declarations. It can optionally
extend one or more other E-interfaces. The einterfaceList,
if given, is a comma-separated list of E-interface names.

The body of the statement is a series of message declarations of the
form:

messageName ( parameters );

Message parameters are declared the same manner as a Java abstract method
declaration.

There is no return type for a message declaration; since E-messages
are one-way, there is no return value.

NOTE: Each E-class implicitly defines an E-interface of its
own, which describes any messages the E-class implements that are not already
declared in its implemented E-interfaces.

Example

ethrow

ethrow expression;

The ethrow statement is similar to Java's throw statement,
except that it throws an E-exception. expression is the E-exception
that is thrown. See the information on the etry statement for
a more detailed discussion of E's exception handling mechanism.

Example

ethrow new RtDirectoryFailure("Directory not available");

etry

The etry statement is similar to Java's try statement.
It contains one or more ecatch clauses that receive E-exceptions
and determine what to do with them. These ecatch clauses collectively
establish a new E-exception handling environment for the execution of trycodeBlock.
Any E-exceptions which are thrown by executing trycodeBlock are
caught here, except those that are caught inside another etry
statement.

Just as the Java exception handling environment follows the flow of
method call and return, the E-exception handling environment follows the
flow of message sends. However, because E-message sends are one-way operations
and E-method invocations are asynchronous, the behavior of E's exception
mechanism differs significantly from Java's.

The exception handling environment established by an etry
statement accompanies any messages sent by trycodeBlock into the
E-methods that process those messages. It will continue to accompany any
messages those E-methods send in turn, unless they establish new E-exception
environments with etry statements of their own.

An E-exception environment persists until all messages within it have
been processed, including any messages spawned by remote objects in response
to messages received from the current environment. In other words, an E-exception
handling environment is responsible for all computation initiated within
its scope, even if remote objects are doing the computing.

Any time an E-exception is thrown (via the ethrow statement),
the exception is caught by whatever E-exception handling environment is
current for the E-method that is executing.

All other non-deferring statements in the code block which contains
the etry, including statements which follow the etry
in the source text, execute before the code blocks associated with the
ecatch clauses, regardless of when any E-exception is thrown as
a result of trycodeBlock.

Unlike Java's try statement, the etry statement cannot
have a finally clause. Also, E does not require your E-methods
to either catch or declare non-runtime E exceptions. Finally, E-exceptions
(which are of class RtEException) are based on the Java RuntimeException
class, not Exception, so they does not encapsulate a back stack
trace.

ewhen

An ewhen statement defers execution of the code it contains
until an actual value is furnished from an E-object. Though similar conceptually
to calling a Java method in that both obtain a value from an object, ewhen's
implementation of optimistic programming make it unique to E; there is
nothing like it in Java.

Since E-methods and E-object cannot return values themselves, you can
use ewhen to get values or other data from other E-objects. This
value can be of any Java type. This means you can use ewhen to
obtain Java values from E-objects, and thus bridge your Java and E code.
For example, you can use ewhen to get a Java integer value from
an EInteger object, and add this value to another Java integer.

expression is an E-object, though this may actually be a channel
to an E-object whose value is undetermined at the time the ewhen
statement is initially executed. After this E-object furnishes a value,
the ewhen code block can execute.

type valuename is the type and name of the value furnished by
expression. Since E-objects cannot return their value like ordinary
objects, you include a value method in the E-object that lets it return
a Java type value. See the following section Getting Java values from
E-objects with ewhen for more information.

An ewhen can only be used inside an E-class, although it does
not need to exist inside an E-method. However, if you use ewhen
inside a regular Java method, you cannot return a value for that method
from within the ewhen statement. This is because the Java method
will actually have returned before any of the blocks associated with the
ewhen gets executed. You can use a return statement
(without a return value) inside an ewhen to exit the ewhen
block.

NOTE: The ewhen statement executes only the first
time a value is furnished. To execute a block of code every time a
value is furnished, use ewhenever.

The ewhen statement is part of a special group of E statements
that defer code execution until a value is furnished for an E-object. These
statements include eif, ewhen, ewhenever, and
the ecatch portion of etry.

All other non-deferring statements in the code block which contains
the ewhen(including statements which follow the ewhen
in the source text) execute before the code blocks associated with the
ewhen, regardless of when the value of expression is produced.

For an ewhen statement that contains no eorwhen clauses
(see the following paragraphs for information on eorwhen), when
expression reveals a value for valueName (which must be of
type type), block executes.

Getting Java values from E-objects

An E-object responds to an ewhen statement by providing a value
for itself. However, an E-object cannot return its value like an ordinary
Java object. Instead, you include a method within the E-object to let it
furnish a Java type value.

To do this, you provide the E-object with a value method.
This is an ordinary zero-argument Java method which should return the E-object's
value. An E-object can return a value of any Java type.

For example, E's own EInteger class, which provides an optimistic
computation wrapper of an instance of Java int, has the following
value method:

int value() { return(myValue); }

(myValue is an instance variable of EInteger which contains
the int that the EInteger is wrapping).

To have an E-object to furnish a value, you must include this value
method in its class definition. Although the value method is not mandatory,
an ewhen statement cannot "access" an E-object that
does not have one.

Closures

When your E program encounters a deferring statement like ewhen,
it takes a snapshot of all the referenced local variables and parameters
within the scope of that statement. This snapshot is called a closure.
E saves this closure for whenever the ewhen needs it; the ewhen
then uses the values in the closure when it executes. Each ewhen
gets its own closure.

Multiway-guarded ewhen statement

If the ewhen statement contains one or more eorwhen
clauses, it becomes a multiway guarded ewhen statement. This means
that the expression associated with block and the various
alternateExpressions associated with the alternateBlocks
are evaluated concurrently. The multiway-guarded ewhen construct
consists of an ewhen clause followed by one or more eorwhen
clauses:

The first code block that is furnished a result has its associated code
block executed and prevents all the other code blocks from executing. Only
one block ever executes. If no values are furnished for any of the expressions,
none of the code blocks execute.

Examples

In this example, Code1 and Code2 do not contain any ewhen,
eif or etry statements. Computation proceeds in the following
order:

Code1 executes.

The two ewhen statements generate messages to obtain values
from Bob and Sue. At this time, SomeEwhenCode
and OtherEwhenCode do not execute, even if the requested values
are available immediately. Instead, computation continues with Code2.

Code2 executes.

If Bob or Sue (or both) have furnished values for
SomeNumber or OtherNumber, respectively, SomeEwhenCode
or OtherEwhenCode can execute. The order of execution of SomeEwhenCode
and OtherEwhenCode depends solely upon which happens to obtain its
argument value first.

If an eorwhen clause had been used in place of the second ewhen
statement, the example would look like this:

In this case the interpretation is very similar to that of the first
example. However, if Bob reveals a value before Sue does,
then SomeEwhenCode will be executed but OtherEwhenCode never
will be. Conversely, if Sue is first to reveal a value, OtherEwhenCode
executes to the exclusion of SomeEwhenCode.

An ewhen statement defines the lexical environment of the
code associated with it, tying it to the value received for the argument.
The values of variables visible to the code inside the ewhen statement
is the same as if it that code had executed immediately. In either of the
above examples, the lexical environment of SomeEwhenCode includes
the value for SomeNumber received from Bob in the message
set up by the ewhen statement. In addition, if SomeEwhenCode
and OtherEwhenCode use variables that are manipulated by both Code1
and Code2, they see only the results produced by Code1.

ewhenever

ewhenever expression ( type valueName ) {
block
}

An ewhenever statement is an ewhen statement which
executes its code block every time it receives a value for its argument.

Multiple executions occur when a channel is forwarded to multiple destinations,
all of which furnish values for the ewhenever argument. An ewhen
statement would execute block only once, the first time a value
is furnished for expression.

The other difference between ewhen and ewhenever
is that an ewhenever statement may not have any eorwhen
clauses, since the mutual exclusion which eorwhen implies does
not really make sense in the context of a statement which executes multiple
times.

See the ewhen statement documentation for complete information
about order of code execution, the lexical environment of block
and so forth.

Like an ewhen, an ewhenever gets a snapshot of all
its variables called a closure. However, an ewhenever's execution
operates on a copy of this closure, not the actual closure itself. This
ensures that the closure retains its original values for the next ewhenever
execution. If your ewhenever statement modifies any of the values
in the closure, those new values are not retained.

Be aware, however, that if your deferring statement references Java
objects, the closure captures the reference to that object, not the value
of the object itself. If your program subsequently modifies the object,
the closure will reference that modified object, and the next ewhenever
will execute using the new value.

forward

distributor <- forward( destinationEObject );

The forward message provides a channel's distributor with a
destination. Once you have forwarded a channel, you cannot unforward it,
though you may forward a channel more than once.

A channel itself is an E-object, derived from class EChannel
(or one of its subclasses). In E, all E-object variables that are not explicitly
initialized in their declarations are implicitly initialized to new instances
of EChannel. These channels are initially unforwarded.

Every channel has a distributor, which can be obtained from
the channel (in the channel's defining scope only) using the distributor
operator, "&" (see the discussion of this operator
at the beginning of this chapter). The distributor is an E-object of class
EDistributor. To forward a channel, send a forward message
to the channel's distributor.

When a channel is forwarded to an E-object, all messages sent to that
channel are delivered to that E-object. You can even send messages to an
unforwarded channel; these messages will be delivered later when the channel
is eventually forwarded.

You can forward a channel to many recipients; all messages sent through
that channel will be received by all the recipients. Messaging is asynchronous:
when you forward a channel to a new recipient, it receives all the messages
that have ever been sent through that channel.

Examples

The most common usage would result from a message send something like
this: