Miranda order

From Erights

(Difference between revisions)
Jump to: navigation, search
(Distinguishing unresolved response from unresolved value)
(let's have an explicit verb type)
(One intermediate revision not shown)
Line 1: Line 1:
{{instance msgdoc|__order|2|<var>verb</var> :[[String]], <var>args</var> :[[List]]|[[any]]}}
{{instance msgdoc|__order|2|<var>verb</var> :[[Verb]], <var>args</var> :[[List]]|[[any]]}}
'''__order/2''' is a [[Miranda message]] for sending messages contingent on an earlier success.
'''__order/2''' is a [[Miranda message]] for sending messages contingent on an earlier success.

Latest revision as of 03:52, 7 August 2011


Signature: __order(verb :Verb, args :List) :any

__order/2 is a Miranda message for sending messages contingent on an earlier success.

This method does the equivalent of

   to __order(verb, args) :any {
       [E.call(self, verb, args), self]

In other words, it calls the receiving object with the message verb(args...), and, if successful, returns a pair of the result of this call and the receiving object itself.

What is this for? Consider the client code fragment

    databaseRcvr <- put(key1, value1)
    def value2Vow := databaseRcvr <- get(key2)

E's partial ordering semantics ensure that put will be delivered before get is delivered. That is often good enough. But it is a weaker guarantee than that provided by the following sequential code

    database put(key1, value1)
    def value2Vow := database get(key2)

In this code, not only will get only happen after put is delivered, get will only happen after put succeeds. If put instead throws an exception, the get will never happen. Often we want this effect. How can we achieve this with eventual-sends to eventual references?

When one wants to take an action contingent on the results of a previous action, the conventional E answer is to use a when-catch-finally expression

   def ackVow := databaseRcvr <- put(key1, value1)
   def value2Vow := when (ackVow) -> {
       databaseRcvr <- get(key2)
   } catch problem {

This is fine, as is probably the solution to be used by default for this situation. However, it does force a round-trip between the get and put, and so loses the benefits of pipelining. Using the __order message, we can get contingent execution + pipelining, at some cost in obscurity. (Note: often, the cost of obscurity will dominate.)

   def pairVow := databaseRcvr <- __order("put", [key1, value1])
   # If put's return value were interesting, we'd 'pairVow <- get(0)'
   def newDBRcvr := pairVow <- get(1)
   def value2Vow := newDBRcvr <- get(key2)

If put throws, then pairVow will resolve directly to broken, so newDB will likewise resolve to broken, as will value2Vow.

Distinguishing unresolved response from unresolved value

It is also possible to use __order to observe when the turn caused by an eventual send finishes, even if its return value is itself an unresolved promise, by waiting for the returned tuple, or its second element, to resolve.

Personal tools
more tools