org.erights.e.elib.prim
Class MirandaMethods

java.lang.Object
  |
  +--org.erights.e.elib.prim.MirandaMethods

public class MirandaMethods
extends Object

Untamed: A sweetener defining default behavior for messages that may be e-called or e-sent to any methodical object. These methods apply directly to null or a "new Object()". Therefore, they must work when self is null.

Author:
Mark S. Miller

Field Summary
private static Class[] NO_CLASSES
           
 
Constructor Summary
private MirandaMethods()
          prevents instantiation
 
Method Summary
static Object __conformTo(Object self, ValueGuard valueGuard)
          Enabled: When a valueGuard doesn't succeed by itself at coercing an object, the valueGuard may enlists the object's aid in bring about a coercion it would find acceptable.
static TypeDesc __getAllegedType(Object self)
          Enabled: Returns a description of the protocol this object alleges to implement.
static SealedBox __optSealedDispatch(Object self, Brand brand)
          Enabled: Generic object-level rights amplification protocol.
static Object[] __optUncall(Object self)
          Enabled: This should return either null or a triple describing a call that, if performed, will create an object resembling this one.
static Object[] __order(Object self, String nestedVerb, Object[] nestedArgs)
          Enabled: For sending messages contingent on an earier success.
static void __printOn(Object self, TextWriter out)
          Enabled: For E, this is the method that should be widely overridden, rather than toString(), since composition via toString() cannot break cycles.
static void __reactToLostClient(Object self, Throwable problem)
          Enabled: When someone was holding a partitionable eventual reference to this object, and it sufferes a partition, then this object is informed that one of its clients may no longer be able to talk to it, and why.
static boolean __respondsTo(Object self, String verb, int arity)
          Enabled: Does this object respond to messages described by verb/arity?
static void __whenBroken(Object self, Object reactor)
          Enabled: Used to implement "Ref whenBroken/2"; it should not be called directly.
static void __whenMoreResolved(Object self, Object reactor)
          Enabled: Used to implement when-catch and the "Ref whenResolved/2"; it should not be called directly.
static Object __yourself(Object self)
          Deprecated. The CapTP comm system no longer makes the use of this described above. If no one sees another need for this, perhaps we can get rid of it?
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

NO_CLASSES

private static final Class[] NO_CLASSES
Constructor Detail

MirandaMethods

private MirandaMethods()
prevents instantiation

Method Detail

__order

public static Object[] __order(Object self,
                               String nestedVerb,
                               Object[] nestedArgs)
Enabled: For sending messages contingent on an earier success.

This method does the equivalent of

     to __order(self, nestedVerb, nestedArgs) :any {
         [E call(self, nestedVerb, nestedArg), self]
     }
 
In other words, it calls the receiving object with the message nestedVerb(nestedArgs...), 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 acheive 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) -> done(_) :any {
         databaseRcvr <- get(key2)
     } catch problem {
         throw(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


__optUncall

public static Object[] __optUncall(Object self)
Enabled: This should return either null or a triple describing a call that, if performed, will create an object resembling this one.

Scalars (ints, float64s, chars, boolean, null) and bare Strings are atomic. __optUncall on an atomic objects return null, but atomic objects are still considered transparent. Objects which return non-null are non-atomic and transparent. Non-atomic objects that return null are opaque. Opaque objects may be selectively transparent to certain clients by using __optSealedDispatch(java.lang.Object, org.erights.e.elib.sealing.Brand) as described there.

When a transpatent non-atomic object is Selfless, then the result of __optUncall is guaranteed to be accurate: It describes a call that, when performed, must result in this very same object, according to E's "==" operation. The Selfless auditor ensures that all Selfless objects are accurately self-describing in this way.

The uncall of a Selfless object is canonical, so if x and y are both Selfless, then

    x == y iff x.__optUncall() == y.__optUncall()

Performing the call described by the uncall of a non-Selfless object generally creates whatever that object wished to create as its representative, but because it had to provide the ingredients, its representative could only be something it could have created. Therefore, the representative cannot convey any more authority than the original object itself has.


__optSealedDispatch

public static SealedBox __optSealedDispatch(Object self,
                                            Brand brand)
Enabled: Generic object-level rights amplification protocol.

Dispatch on the brand much as one would dispatch on a message name. If we recognize the brand and we have the corresponding sealer, then we may return something meaningful inside a SealedBox sealed with that Sealer. If we have nothing to return, given the meaning we associate with that brand as a request, then we return null.

Something meaningful? Sounds strange. See [e-lang] Object coercion / adaptation and the surrounding thread for more on the rationale for the design of this method. Note that, at the time of that discussion, this method was named getOptMeta instead.

The default implementation: If self is Amplifiable, delegate to it. Otherwise, return null.

If this object isn't actually transparent, but if brand represents a party this object would like to reveal itself to (such as a serialization system implementing persistence for this object's subsystem), then this object can choose to return a SealedBox, sealed by the by the Sealer for that brand, containing the same triple that __optUncall(java.lang.Object) would otherwise have returned. By so doing, the object reveals its internals only to someone having the corresponding Unsealer.


__getAllegedType

public static TypeDesc __getAllegedType(Object self)
Enabled: Returns a description of the protocol this object alleges to implement.


__respondsTo

public static boolean __respondsTo(Object self,
                                   String verb,
                                   int arity)
Enabled: Does this object respond to messages described by verb/arity?


__printOn

public static void __printOn(Object self,
                             TextWriter out)
                      throws IOException,
                             NoSuchMethodException
Enabled: For E, this is the method that should be widely overridden, rather than toString(), since composition via toString() cannot break cycles. The Miranda method defaults to java-calling String.valueOf(self) and write()ing the result on out. String.valueOf(self) is java's null-safe form of self.toString();

IOException
NoSuchMethodException

__reactToLostClient

public static void __reactToLostClient(Object self,
                                       Throwable problem)
Enabled: When someone was holding a partitionable eventual reference to this object, and it sufferes a partition, then this object is informed that one of its clients may no longer be able to talk to it, and why.

The Miranda behavior is to do nothing, but objects may override this to provide DeadManSwitch behavior. For example, a revoking facet of a revokable service may decide that if its client may no longer be able to talk to it, that it should auto-revoke. However inconvenient this solution, it is failsafe.


__whenMoreResolved

public static void __whenMoreResolved(Object self,
                                      Object reactor)
Enabled: Used to implement when-catch and the "Ref whenResolved/2"; it should not be called directly.

The Miranda behavior responds by doing 'reactor <- run(self)'. If the reference never becomes resolved, the reactor is not invoked.

In the cooperative (non-malicious) case, the reactor will not be invoked more than once. When sent on a reference, once the reference becomes resolved the reactor will be invoked with the resolution. Should the reactor be invoked with a non-broken reference, all earlier messages are guaranteed to have been successfully delivered.

Should the reference become broken, or should breakage prevent the reporting of fulfillment to the reactor, the reactor will be invoked with a broken reference. The reactor may be invoked more than once. In particular, if the reference becomes fulfilled and then broken, the reactor may hear of either or both of these events.

See Also:
org.erights.e.elib.ref.Ref#whenBroken

__whenBroken

public static void __whenBroken(Object self,
                                Object reactor)
Enabled: Used to implement "Ref whenBroken/2"; it should not be called directly.

The Miranda behavior ignores the message, as only breakable ref implementations ever respond to this message.

See Also:
Ref.whenBroken/2

__yourself

public static Object __yourself(Object self)
Deprecated. The CapTP comm system no longer makes the use of this described above. If no one sees another need for this, perhaps we can get rid of it?

Enabled: When invoked on a methodical object, the object should simply return itself.

Although the name and the semantics are borrowed from Smalltalk, the purpose is completely different. This method is used by distributed three vat handoff to implement the poE ordering guarantees: When Alice sends to Bob a reference to Carol

    E.sendOnly(bob, "foo", carol)
when each is on a different machine, the encoding of Alice's Far reference to Carol instead encodes the value returned by
    E.send(carol, "__yourself")
Any messages sent to this result will only be received by Carol after Carol receives the "__yourself" message, and therefore after Carol has received all messages which precede the "youself" message. This is true even if the messages sent to the result are sent from another machine, as would be the case in distributed three vat handoff.

Since all this results in a system which successfully implements poE, users of ELib other than captp should never need to invoke this method, and no one should ever need to override it. If we do make some miranda methods non-overridable, we would make __yourself/1 non-overridable.


__conformTo

public static Object __conformTo(Object self,
                                 ValueGuard valueGuard)
Enabled: When a valueGuard doesn't succeed by itself at coercing an object, the valueGuard may enlists the object's aid in bring about a coercion it would find acceptable.

A valueGuard enlists the object's aid at the price of being Gozarian. A Gozarian valueGuard wants to enlists the object's aid because it is ignorant of the kind of object it's dealing with, so a generic protocol is needed. That's why __conformTo/1 is provided as a MirandaMethod.

The valueGuard asks the object to conform to some valueGuard that the object may know about. Often this will be the valueGuard that's attempting the coercion. An object should attempt to return a representation of itself that the argument valueGuard would succeed in coercing. A requesting valueGuard should then try again on the result, but if this doesn't coerce, it should fail there rather than making further __conformTo/1 requests. This implies that it's the responsibility of the object's __conformTo/1 implementation to do any iteration needed for multi-step conversions.

The default (Miranda) implementation of __conformTo/1 just returns self.



comments?