|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object | +--org.erights.e.elib.prim.MirandaMethods
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.
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 |
private static final Class[] NO_CLASSES
Constructor Detail |
private MirandaMethods()
Method Detail |
public static Object[] __order(Object self, String nestedVerb, Object[] nestedArgs)
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
public static Object[] __optUncall(Object self)
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.
public static SealedBox __optSealedDispatch(Object self, Brand brand)
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.
public static TypeDesc __getAllegedType(Object self)
public static boolean __respondsTo(Object self, String verb, int arity)
public static void __printOn(Object self, TextWriter out) throws IOException, NoSuchMethodException
IOException
NoSuchMethodException
public static void __reactToLostClient(Object self, Throwable problem)
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.
public static void __whenMoreResolved(Object self, Object reactor)
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.
org.erights.e.elib.ref.Ref#whenBroken
public static void __whenBroken(Object self, Object reactor)
The Miranda behavior ignores the message, as only breakable ref implementations ever respond to this message.
Ref.whenBroken/2
public static Object __yourself(Object self)
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.
public static Object __conformTo(Object self, ValueGuard valueGuard)
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.
|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |