ERights Home elang / kernel 
Back to: Immediate Call Expression On to: Object Expression

Eventual Send Expression

Ask the recipient to eventually perform the action named verb as parameterized by the argumens, but not now. Queues a pending delivery of this message to this recipient to happen in the recipient's vat, and in its own turn.

eExpr "<-" Verb ["(" eExpr ("," eExpr)* ")"]
<!ELEMENT sendExpr (%eExpr;, Verb, (%eExpr;)*)>
E.send(jExpr, "verb", jExpr...)
observer <- noticeChange(delta)
in Kernel-E:
in XML:
in Java:
E.send(observer, "noticeChange", delta)

The reference to the recipient is the value of the expression on the left and the arguments are the values of the expressions between the parens. As is typical in E, expressions are evaluated left to right, and variables defined on the left are visible on the right. The reference to the recipient attempts to convey the message to the recipient. If it succeeds, the message is delivered to the recipient in its own turn. The send expression itself always immediately evaluates to a value -- it never performs a non-local exit. The value of the send expression is a reference to the result of the eventual delivery.

Partially Ordered Fail-Stop Delivery

Successive messages sent on the same reference must be delivered in the order sent. Since distributed systems do not allow for reliable message delivery channels, an EVENTUAL reference instead must be fail-stop: reliable up to the first failure to deliver, and it must never deliver any more messages. Therefore, a successful delivery demonstrates that earlier messages sent on the same reference must have been delivered. A failed reference must eventually become BROKEN.
See also Two Party Full Order.

When a reference is included within an argument of a send, we say the reference has been forked, and that what is received is not the sent reference but a fork of the sent reference. Messages sent on a reference before it is forked must be delivered to the recipient prior to message sent of the reference after the fork of course, but also prior to messages sent on that fork of the reference. Messages sent on the original reference after the fork, and messages sent of the fork, represent two separate full orders. These messages may be delivered in any interleaving of these orders.
See also Three Party Tree Order.

Given two references, x and y, that designate the same recipient, "E join(x, y)" returns a new reference that also designates that recipient. Messages sent on either x or y prior to the join must be delivered prior to messages sent on the joined reference. The joined reference itself is simultaneously a fork of x and y -- if messages are sent on all following the join, these messages may be delivered in any interleaving of their respective orders.
See also Four Party Partial Order.

Of course, if a reference should fail prior to a fork or join, the fork or join of the reference is born failed, it may not deliver any messages, and it must eventually become BROKEN.

Delivery by Reference Type

To understand the behavior of send in detail, it's useful to break it down according to the type of reference to the recipient.

  • NEAR. If the reference is NEAR, then the recipient is in the same vat as the sender, and the reference is reliable up to crash/revival. A send queues the pending delivery in this vat's pending delivery queue, which won't get serviced until the current turn is done. The send evaluates to a promise for the outcome of the delivery. The delivery can only exit by evaluating to a result, in which case this becomes the resolution of the promise, or by throwing a problem, in which case the promise becomes BROKEN with this problem.

    The holder of the promise, if he sees it become BROKEN, cannot assume the recipient threw, as the recipient may instead have returned a BROKEN reference as its normal result. Similarly, if the promise remains EVENTUAL, the holder of the promise cannot assume that delivery hasn't happened yet, as the recipient may have returned an EVENTUAL reference as its normal result. This ambiguity is intentional -- it allows better abstraction of the recipient's duties.

  • BROKEN. If the reference is BROKEN, it will not deliver any messages, and the problem associated with the reference attempts to explain why not. A send to a broken reference evaluates to a reference broken with the same problem -- which can often be the same reference.

  • Far reference (EVENTUAL, Resolved). A Far reference is a reference to a specific recipient in a foreign vat. If a far reference succeeds at delivering the message, the message is queued in the foreign vat for eventual delivery to the recipient. Although this delivery may happen while the sending turn is still in progress, because the two vats have no synchronous access to each other, these are still isolated transactions. Side effects in the receiving turn can have no effect on the sending turn.

    A send on a Far reference immediately evaluates to a promise for the outcome of the delivery. All the outcomes explained for NEAR reference are possible. In addition, if the promise becomes BROKEN with a PartitionException, then either

    1. The inter-vat connection failed, preventing the delivery of the message.

    2. The inter-vat connection failed, preventing the promise from resolving to the actual outcome.

    3. The outcome of the delivery was indeed either a reference broken by a PartitionException or a throw of a PartitionException.

    This ambiguity is intentional. It is a fundamental constraint of distributed systems that cases #1 and #2 cannot be distinguished. Case #3 may result from the recipient in turn experiencing a communications problem in its own subcontracting of parts of the job. This protocol allows such problem reports to propogate to interested parties.

  • Promise (EVENTUAL, Unresolved). A promise doesn't yet know who the recipient is, but is nevertheless a conveyance for sending messages to whoever it turns out to be. Messages sent on a promise queue up in the promise itself until the promise is resolved -- until a reference to the recipient is determined. At this point, the messages are resent on this reference, which may recursively be any of these cases. It is equivalent for a promise to become broken and for it to resolve to a broken reference. Promises come in two flavors:

    1. A LocalPromise has both the Ref end (the tail of the arrow) and the Resolver end (the head of the arror) in the same vat, so it is reliable up to crash/revive.

    2. A FarPromise spans vats, and so is reliable only up to partition.


Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home elang / kernel 
Back to: Immediate Call Expression On to: Object Expression
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign