|
When we first created lazyNum, where did the "<lazy>"
string that was printed out come from? After the E
command interpreter reads and evaluates an expression, it then needs to
print a string to represent the resulting value. It gets this by calling
the result's __printOn method
? pragma.syntax("0.8")
? def makePoint(x, y) :any {
> def point {
> to __printOn(out) :void { out.print(`<$x, $y>`) }
> to getX() :any {x}
> to getY() :any {y}
> }
> }
# value: <makePoint>
? def pt := makePoint(3, 5)
# value: <3, 5>
? pt.__printOn(stdout)
# stdout: <3, 5>
? makePoint.__printOn(stdout)
# stdout: <makePoint>
Above, the object expression for point explicitly
provides a __printOn method, and this is what gets run when __printOn
is called on a point. The object expression for makePoint, on
the other hand, does not provide a __printOn method, but nevertheless,
we see that it has a __printOn behavior. __printOn is
one of a small set of Miranda Methods -- if the object-expression does
not supply its own __printOn method, one will be provided for
it. Similarly for the other Miranda Methods.
Rarely, in order to have full control, you may wish to
define an object while waiving all your miranda rights, rather than just
overriding individual methods. You do this by using a plumbing
expression instead of an object expression.
The Miranda Methods can also be used from ELib, as documented
here.
(There is a distressing amount of redundancy between
that page and this one. We need to fix this, probably when we build edoc.)
The Miranda Methods are:
The Miranda Methods are actually implemented in Java and
operate from within the E implementation.
A few rely on that special position to implement behaviors that could
not otherwise have been implemented in E.
In this section, we will do our best job of using E
anyway as a notation to explain what these methods do, but explain in
the text what the differences are.
-
__printOn(out)
Asks the object to print a representation of itself onto the TextWriter,
using "out.print()" and its
siblings. The object should print subobjects by sending them
to the same TextWriter (or any indentation of it) rather than coercing
these to a string itself, in order to give the TextWriter the opportunity
to finitely print cyclic
structures.
The Miranda behavior is
to __printOn(out :TextWriter) {
out.print("<", , ">")
}
except that an E object
has no other way to ascertain the name of its defining object expression.
If the defining object expression is anonymous, then the object
prints as
<e object>
- __whenMoreResolved(observer)
Really used to test a reference rather than an object. When sent
to a Promise, should the Promise ever become Resolved, the resolution
is eventually sent to observer. If it is sent to a Far reference,
even though a Far reference is already Resolved, the __whenMoreResolved
message will still be sent to the object the Far reference designates,
so that it can respond. This ensures that a __whenMoreResolved does
not report successful resolution (notifying the observer with a
non-Broken argument reference) until all earlier messages sent on
this same reference have been received.
The when/catch construct expands
into a call to "Ref.whenResolved(...)", which sends __whenMoreResolved.
The Miranda behavior is
to __whenMoreResolved(observer) {
observer <- run(self)
}
- __whenBroken(observer)
Used to ask a reference to notify the observer should it
ever become broken. By virtue of the behavior below, a Near reference
ignores the request, since it cannot become Broken. A Broken reference
immediately responds with itself. Eventual references, whether Resolved
or not (whether a Promise or a Far reference) remember the request
so they can notify the observer should they become Broken. In all
cases, of the observer is invoked, it is eventually send the Broken
reference as the argument of a run message.
The Miranda behavior is
to __whenBroken(observer) {}
- __order(nestedVerb,
nestedArgs) => [result, self]
Without the order message, E
already provides for the partially-ordered fail-stop delivery of messages
sent on the same reference. However, this notion of fail-stop only
makes later delivery contingent on the reference remaining unbroken.
You can use the order message to get the same effect, but have later
deliveries contingent on the synchronous success of an earlier message
as well.
The Miranda behavior is equivalent to:
to __order(nestedVerb, nestedArgs) :any {
[E.call(self, nestedVerb, nestedArg), self]
}
If the call throws, then the order message as a whole throws. A
promise for the result of an order message becomes broken, rather
than resolving to a pair of a broken promise and self.
? def x := 6 <- __order("floorDivide", [2]) <- get(1) <- add(2)
# value: <Promise>
? x
# value: 8
8 is indeed 6 + 2.
? def y := 6 <- __order("floorDivide", [0]) <- get(1) <- add(2)
# value: <Promise>
? y
# value: <ref broken by problem: <ArithmeticException: / by zero>>
We never asked 6 what the "+ 2" of itself is, because the
earlier floorDivide threw an ArithmeticException.
Therefore, the promise for the result of the __order/2 message
became broken by this exception, as did the promise for the get/1
message sent to this promise, and the promise for the add/1
message sent to that promise. This contingency of the latter operation
happened without waiting on a round trip to find out about the earlier
operation, and so still made full use of pipelining.
- __getAllegedType()
getAllegedType, which will return a Type object
describing the protocol that this object alleges it responds to.
The Miranda behavior is
to __getAllegedType() :Type {
}
- __respondsTo(verb,
arity)
Does this object respond to messages with this verb
and this arity?
The Miranda behavior is equivalent to
to __respondsTo(verb :String, arity :int) :boolean {
self.__getAllegedType().hasMethod(verb, arity)
}
- __yourself()
Used internally by CapTP
to ensure that message are delivered in the proper order when Alice,
Bob, and Carol are on three separate machines. Is available for use
by the E programmer, but
it's hard to see when it would be useful. It you find a programming
technique that makes use of yourself, please let me, the webmaster-at-erights.org,
know.
The Miranda behavior is
to __yourself() :any {
self
}
- __reactToLostClient(problem)
Informs the object that at least one of its clients may no longer
be able to communicate to it, due to a network partition.
To be written. See Dead-Man
Switch.
- __optSealedDispatch(brand)
Generic object-level rights amplification protocol.
To be written.
|
|