Walnut/Distributed Computing/Partial Ordering Of Sent Messages

From Erights

Partial Ordering Of Sent Messages

The above example moves the carRcvr around repeatedly and then asks for the amount of fuel remaining. This displays another important property of eventual sends: if object A sends several messages via a single reference to object B, it is guaranteed that those messages will arrive and be processed in the order of sending. This is only a partial ordering, however. From B's point of view, there are no guarantees that the messages from A will not be interspersed with messages from C, D, etc. Also, from A's point of view, there are no guarantees that, if A sends messages to both B and C, the message to B will arrive before (or after) the message to C, regardless of the order in which A initiates the messages. Furthermore, if A happens to have 2 different references to B (such as 2 promises that both will eventually resolve to B), the guarantee only applies to messages being sent down one reference.

Despite those uncertainties, however, in the example the partial ordering is sufficient to guarantee that fuelPromise will resolve to the quantity of fuel remaining after all three of the moveTo() operations have occurred. It also guarantees that those moveTo()s will have been performed in the specified sequence.

On first introduction, it is hard to fully appreciate the relationship between partial ordering and when-catch delayed activation. Here is a more sophisticated example.

# E syntax
def cars := [car1,car2,car3]
for each in cars {
def nameVow := each <- getName()
def moveVow := each <- moveTo(3,4)
when (nameVow, moveVow) -> {
println(`Car $nameVow has arrived`)
} catch e {println("A car did not make it")}
}
println ("Cars have been told to move, but no print of any arrivals has yet occurred")

In this example, getName and moveTo messages are sent to all the cars in the list in rapid-fire succession, never waiting for any answers to get back. The "Cars have been told to move" message at the bottom is guaranteed to print before any "has arrived" messages print. We cannot predict which of the 3 cars will arrive first, second, or third. It all depends on where they are running, how slow the connections are, how loaded the processors are. We cannot even predict which will receive the moveTo message first: though the program is guaranteed to fire off the message to car1 first, the processor upon which car1 executes might be several thousand miles away across the Internet, across a dozen bottlenecked routers. And car2 could be running on a computer two feet away, a short hop down an Ethernet connection. In that case car2 would probably be first to receive its message, and be first to actually arrive, and be the first to return its resolution so the arrival message could print--all three of those events being independent, and the first car to do one is not necessarily the first car to do the next.

Meanwhile, it is guaranteed that each car will get the getName message before it gets the moveTo message. It is not guaranteed that the nameVow will resolve to an answer before the moveVow has resolved, so you must use a multi-vow when-catch to use the name inside the when body with confidence. And if the moveTo promise is broken, which activates the catch clause, we do not know the resolution of the name--it could have fulfilled before the moveTo promise broke, or the name promise could be waiting (and on the verge of being broken or fulfilled) as well. We could use the E isBroken() function described later if we wanted to try to print the name of the car in the catch clause in those situations where the name was fulfilled though the moveTo was broken.

Also it is worth noting that the moveTo method, when used in an eventual send, returns a promise even though the moveTo method is of type "void" (i.e., "does not return a value"). This promise, if fulfilled, will always become the uninteresting value of null...but as shown in this example, sometimes it is valuable to know that fulfillment has occurred, or that fulfillment has failed, even if you do not care what the fulfilled value may be.

Sometimes you want to ensure that car1 arrives before car2, and car2 before car3. In a simple problem you could use nested when-catches, described later. In this example, where you don't necessarily know how many cars there are, you would use the recursive when-while pattern or the sendValve utility, both described at the end of the chapter.