[squeak-dev] Inbox: #future keyword for asynchronous message
josh at schwa.ca
Thu Dec 17 11:02:59 UTC 2009
I just uploaded 4 packages to the inbox:
It seems to be OK to load in that order for testing, but if we decide to include this in the trunk, I'll devise a bullet-proof load order (not to mention writing some unit tests). But hey, at least there are good class comments!
What is this about? It's about convenient syntax for sending and obtaining results from asynchronous messages. The initial use-case in the trunk image is to have shorter code where we currently use #addDeferredUIMessage:; you can see a few such transformations in the Network and System packages. It probably doesn't pay it's way with this use-case alone, but the exciting future use-cases are to support more advanced concurrency constructs.
This code originated in Croquet as a convenient syntax for sending messages to replicated objects over the internet. We continue to use (an evolved version of) it at Qwaq/Teleplace, and have also layered other concurrency constructs on top of it. Many more uses are possible. For example, it would be very useful in a Hydra system to send messages to objects residing in other object-memories.
How does it work? This is an extension to the Compiler, plus a small amount of support code in Object and Project. Eliot left hooks for FutureNode in Compiler, so all we need to do is add FutureNode to the system (good, because I'm no compiler expert!).
How do you use it? It's getting late, so I'll just paste the class comment from FutureNode.
Compile-time transformation of #future and #future: messages. Use is best described through examples:
receiver future doSomething: arg1 withArgs: arg2.
(receiver future: 2000) doSomethingElse
The first means to immediately schedule #doSomething:withArgs: for asyncronous evaluation. The second means to wait 2000 milliseconds before scheduling #doSomethingElse for asynchronous evaluation.
These are transformed into either #futureDo:at:args: or #futureSend:at:args:, depending on whether the result is used. Let's look at a few examples.
[receiver future foo. 2+2] value.
true ifTrue: [^receiver future foo].
arraySize := receiver future getArray wait size.
In the first case, the result is never used, so the message #futureDo:at:args: is generated. In the second case, the result is answered from the current method. Since we don't do any cross-method analysis, we have to assume that the result is needed for a later computation. The result is provided in the form of a Promise, which will resolve to a value when the asynchronous evaluation has completed. Creating and resolving this Promise is the responsibility of #futureSend:at:args:, which is generated instead of #futureDo:at:args: when code-analysis indicates that the result of the message might be used. The third example is another one where #futureSend:at:args: is generated.
See the default implementations of #futureDo:at:args: and #futureSend:at:args: in Object. Subclasses are free to override the default implementations to achieve specific effects. For example, this functionality originated in the Croquet class TFarRef. If you have a TFarRef to a replicated object, then sending 'aTFarRef future foo' results in a message being sent over the network to each replica of the object referenced by aTFarRef. We might also use far-refs, for example, to send a message to an object in another Hydra object-memory.
I should probably quit now, because I need my beauty-sleep. Hopefully this is enough to get a discussion going; I'll respond tomorrow.
More information about the Squeak-dev