Concrete definitions may be bound to slots via {...}. A
special form, <> is used instead to indicate that a slot is
bound to a concrete definition only upon construction. It is used only
for ``stored'' functional slots that access a single value that must
be intialized upon construction.

Computation is based on message passing. Objects are autonomous
single-threaded computational agents that send messages listed within
operations corresponding to messages from other objects. A
message is a record that corresponds to a declared operation.
ODL op declarations define records with names identical to
operation names, and fields corresponding to argument lists. There
are five phases in any act of message passing:

Invocation.

An invocation listed in the concrete definition of a sender is
issued.

Reception.

ODL does not specify the mechanisms
controlling how messages are issued and received by objects
except in the assumption that they do not interfere with
explicitly defined processing. Synchronicity between sending and
receiving a message is neither required nor precluded.

Binding.

A message is linked with a corresponding
operation or version of an operation. Linkage may be determined
either statically or dynamically. (Run-time binding is
necessary when there are argument-based guard conditions.)
Binding failures cannot occur in correct programs.

Acceptance.

An accepted message is ``consumed'', and causes
the triggering of an operation when its guard has cleared.

Execution.

Computation proceeds by noninterruptibly processing
all actions defined in the corresponding concrete operation.

The simplest form of a concrete operation is a sequence of one-way
message sends, for example, { a.m1(x); b.m2(y, z); ... }.
Invocations are defined by by naming them and providing field values
along with a recipient designation. Instead of recipient prefixing,
ODL messages may also be invoked with an indication of a class
of receivers, via className $ message.
Stylistically, this form is useful for stateless services for which
the identity of the recipient cannot matter. The run-time system is
free to select any instance of the indicated class (or any subclass
thereof) to receive the message. ODL does not prescribe a
particular translation mechanism. Several are available. For example,
because all occurrences of $ are statically determinable before
execution, the system may construct a pool of such objects upon
initialization and translate all invocations to normal prefixed form.

Here, the sender enters a state in which its only next action is to
receive a corresponding reply. A catch clause introduces one or
more transiently available operations that accept replies from
servers. Multiple named result messages and catches are also allowed.
The names of the client operations must match those listed for the
server. Translators must arrange that result operations be caught
only when objects are in the required state.

A server object invokes these transient messages by name:

class A op m1(x: T) : result(b: B) { ...; result(new B); } end;

The recipient of the reply is left implicit. This logically requires
that sender identity be transmitted as an implicit argument in all
procedural messages. However, in ODL the sender identity is not
otherwise accessible to the server. (Unless, of course, a sender field
is explicitly added to the operation signature and used in the desired
ways.) A server may perform additional actions after issuing a reply.

This declares the result of a as an anonymous record with single
field i and the result of b as an anonymous, fieldless
record. Each anonymous record is considered to have a different name.
Anonymous return messages are sent via reply:

Here, the anonymous catch may be elided, and the reply used
directly in a procedural fashion.

Simple blocking procedural interaction is the only two-way protocol
natively supported in ODL. Others may be defined through
combinations of one-way sends and object constructions. For example, a
future may be defined via the construction of a helper object to
wait out a procedure.

Functional operations have a restricted form. They are defined as
single expressions using the value expression sublanguage described in
section 3.2.3. Translators are required to transform
functional expressions into procedural computations (possibly
involving new independent, unreachable objects) that cannot interfere
with other operations and objects.

Stored functions are yet further restricted. They may be defined only
via <>, indicating that a stored value be attached upon
construction, retrieved upon access, and possibly rebound in the
course of other operations. Stored links may also be qualified as
packed. This is a hint to the translator that the object
referenced by the slot should be embedded within the representation of
the host object.

The base form of stored values is restricted to link values, not other
types. The reflects an underlying object model in which state varies
only as a function of connections among objects. Other forms may be
implemented with the help of instances of elementary predefined
classes. However, ODL programmers are not required to do so
themselves. Translators may mechanically reduce them to base form. A
stored value denoting a non-link type may be translated to one holding
a link to an instance of a predefined class, where value accesses are
forwarded to these objects. Value rebindings may be translated either
to link rebindings of new objects with the required initial values or
to set operations on the exisiting objects, or any other
technique, at the discretion of the translator. Bindings of the form
l := null for opt slots are handled similarly.

ODL local operation invocations are not received as
messages. They are sequentially executed in the course of performing
other actions. To avoid the need for redundant declaration, a
local version of each functional non-local operation is automatically
constructed if not otherwise present. Local operations must be invoked
without a recipient prefix. (In contrast non-local self-invocations
must be prefixed with self.)

Local functions and procedures may in turn invoke others, and may be
recursive. Standard procedural invocation rules and semantics apply.
One-way local operations are also allowed. Invocations are
interpreted as structured ``gotos'' in which control does not return
to the calling operation. For this reason, procedural operations may
not invoke local one-ways.

The execution state of objects is in general unbounded. The existence
and value of representational bounds for particular classes and
objects may be conservatively assessed via static analysis of
local operations. When bounds are not discerned or discernable,
ODL implementations may establish maximal per-object run-time size
limits and handle overflow as a run-time error.

Every instantiable class declaration automatically results in the
definition of a corresponding new operation in class
System. The new operation has arguments corresponding to all
slots declared as <>, and returns a unique link value
referencing an object of the indicated class. Implementations of
new (as well as delete) are not definable within ODL,
although provision of implementation-specific blob-based classes
and object layout rules may make them so.

Without qualification, the class's new operation may be invoked
anywhere. The visibility of new may be controlled via a
generator clause in a class declaration. A generator clause
names the classes of entities that may invoke new for the class.

ODL message passing rules assume preservation of referential
integrity. Objects that may still receive messages may not be deleted.
This is best implemented using automatic storage management (garbage
collection). However, a delete operation is also associated with
each concrete class. Visibility is also controlled via generator.