Source

newspeak / Past.ns3

Full commit
Gilad Bracha 2b5bcc9 

Ryan Macnak c9c7d23 
Gilad Bracha 2b5bcc9 










Gilad Bracha 40fe69c 
Gilad Bracha 2b5bcc9 


















Ryan Macnak 28ffe0d 
Ryan Macnak c9c7d23 
Gilad Bracha 2b5bcc9 

Ryan Macnak c9c7d23 
Gilad Bracha 2b5bcc9 













Ryan Macnak fac3519 


Gilad Bracha 2b5bcc9 




Ryan Macnak c9c7d23 
Gilad Bracha 2b5bcc9 
Ryan Macnak ced85bd 



Gilad Bracha 2b5bcc9 










Ryan Macnak c9c7d23 
Gilad Bracha 2b5bcc9 











Ryan Macnak 2ce7d32 
Gilad Bracha 2b5bcc9 






Ryan Macnak c9c7d23 


Gilad Bracha 2b5bcc9 









Ryan Macnak ced85bd 



Ryan Macnak 9dc9308 







Ryan Macnak 830acf8 
Ryan Macnak 9dc9308 
Ryan Macnak 4c2127e 








Ryan Macnak 9dc9308 
Ryan Macnak 2215c73 
Ryan Macnak 9dc9308 


Ryan Macnak 4c2127e 








Ryan Macnak 9dc9308 


Ryan Macnak 4c2127e 
Ryan Macnak 830acf8 
Ryan Macnak 4c2127e 

Ryan Macnak 9dc9308 
Ryan Macnak 4c2127e 
Ryan Macnak 2215c73 

Ryan Macnak 4c2127e 
Ryan Macnak 9dc9308 




Ryan Macnak 4c2127e 



Ryan Macnak 9dc9308 
Ryan Macnak 4c2127e 



Gilad Bracha 2b5bcc9 


























































Ryan Macnak 8ff3cfa 





Newspeak3
'Past'
class Past usingPlatform: platform = (
	"
Who controls the past controls the future;
who controls the present controls the past
  - George Orwell, 1984

Past is a library implementing futures. Futures are essential in Newspeak. They are used to implement mutually recursive slots, and for actor based concurrency. They are the foundation of laziness.

This module contains a number of variants of futures, including simple lazy objects (Delay),  pipelining futures (Future, UnresolvedFuture) and remote futures. Futures resolve into forwarders (Forwarder, ResolvedFuture).

This API is still very experimental.

Copyright (c) 2010-2012  Gilad Bracha. 

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the ''Software''), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ''AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE."| 
"imports"
private List = platform collections MutableArrayList.
private ObjectMirror = platform mirrors ObjectMirror.
|)
(
class Delay computing: c <[]> = (
"A simple future that delays a computation. It accepts a closure, and evaluates it when it receives a message. Rather than track whether it has been resolved or not, it changes its class to a Forwarder when it resolves."|
	contents ::= c.
|)
('as yet unclassified'
computation ^ <[]> = (
	^contents
)
doesNotUnderstand: msg <Message> ^ <Object> = (
	^msg sendTo: resolve
)
forwardee ^ <Object> = (
	^contents
)
resolve ^ <Object> = (

	computation isBlock ifFalse: [^computation].

	contents:: computation value.
	(ObjectMirror reflecting: self) setClass: Forwarder ifFail:[].
	^forwardee
)
yourself = (
	#BOGUS. "This is used by mixin application to force resolution. (Superclasses must be the real object, not a proxy, for the VM.)"
	^self resolve
)) : ('as yet unclassified'
computation: block = (
	^self computing: block
))
class Forwarder forwardingTo: f = (
"A transparent forwarder. Needs to override all Object protocol to be totally transparent."|
forwardee = f.
|)
('as yet unclassified'
doesNotUnderstand: msg <Message> ^ <Object> = (
	^msg sendTo: forwardee
)
yourself = (
	^self forwardee
)) : ()
class Future computing: c <[]> = (
"A future implementation of pipelined promises that does not rely on changing its class to change its state.  This should be contrasted with UnresolvedFuture, which when resolved, converts itself to a ResolvedFuture.

The advantage is that there is less reliance on reflective magic in this version. The disadvantage is that each future object carries two extra slots "| 
	computation <[]> = c. 
	resolved ::= false.
	dependents <List[Future]> ::= List new.
	forwardee 
	|)
('as yet unclassified'
doesNotUnderstand: msg <Message> ^ <Object> = (
	| pipelinedPromise <Future>  |
	pipelinedPromise:: Future 
		computing: [self perform: msg selector withArguments: msg arguments].
	dependents add: pipelinedPromise.
	"need to register piplelinedPromise so we can resolve it when self resolves"
	^pipelinedPromise
)
futureClass ^ <Future class> = (
	^Future
)
isFuture ^<Boolean> = (
	^true
)
resolve ^ <Object> = (
	| r |
	resolved ifFalse:[
		r:: computation value.
		forwardee:: r isFuture ifTrue:[r resolve] ifFalse: [r].
		resolved:: true.
		dependents do:[:d <UnresolvedFuture> | d resolve].
		dependents:: nil.
		].
	^forwardee
)) : ('as yet unclassified'
computation: block = (
	^self computing: block
))
class Future2 computing: b state: s = ("An alternative future for simultaneous slots. It aims to be lazier than Delay but more eager than Future by attempting to resolve on the first incoming message but answering pipelined futures for messages received during resolution.

States:
	unresolved - the future used to initially fill simultaneous slots: attempt to resolve when a message is received
	unresolvedDependent - the futures created by pipelining: pipeline again when a message is received
	resolving - pipeline when a message is received; complain if asked to resolve again
	resolved - forward messages to forwardee
	
Seems to work for both cases of mutual imports and successfully detected a trivial example of divergent evaluation.  IDE hits a divergent resolution: something is too eager :(
"|
	state ::= s.
	block ::= b.
	dependents
	forwardee
|)
('as yet unclassified'
doesNotUnderstand: message = (
	
	state == #resolved ifTrue: [^message sendTo: forwardee].
	state == #unresolved ifTrue: [^message sendTo: self resolve2].
	(state == #resolving) | (state == #unresolvedDependent) ifTrue: [
		| f = Future2 
			computing: [message sendTo: self resolve2] 
			state: #unresolvedDependent. |
		dependents add: f.
		^f].
	
	Error signal: 'Invalid future state'.
)
isFuture = (
	^true
)
resolve = (
	^self "Ignore the resolve inserted by the compiler for now."
)
resolve2 = (
	state == #resolved ifTrue: [^forwardee].
	(state == #unresolved) | (state == #unresolvedDependent) ifTrue: [
		state:: #resolving. dependents:: List new.
		forwardee:: block value.
		forwardee isFuture ifTrue: [forwardee:: forwardee resolve2].
		state:: #resolved.
		dependents do: [:each | 	each resolve2].
		dependents:: nil.
		^forwardee].
	
	state == #resolving ifTrue: [
		Error signal: 'Divergent resolution of a future!'.
		"Does this detect all divergent evaluation?"
	].
	
	Error signal: 'Invalid future state'.
)
yourself = (
	^self resolve2
)) : ('as yet unclassified'
computing: b = (
	^self computing: b state: #unresolved
))
class RemoteFuture computing: c <[]> = (
"A future made available to another actor. The RemoteFuture is simply a wrapper for an actual future elsewhere. It cannot be directly asked to resolve itself, or to divulge whether it is resolved or not. Instead, it is associated with a separate object, a Resolver, which can resolve it.

This probably belongs in the Actor module.
 "| private contents = UnresolvedFuture computing: c. |)
(
class Resolver = (
"An instance of this class is a distinct capability for resolving the enclosing future.  In an actor system, futures are made available to other actors as the result of asynchronous message sends. These futures are instances of the enclosing class, RemoteFuture.  They cannot be resolved by the sending actor; rather, the actor system will resolve them when the required computation is done. To that end, the actor system will be given a resolver (an instance of this class) for the future in question")
('as yet unclassified'
resolve ^ <Object> = (
	^contents resolve
)) : ()'as yet unclassified'
doesNotUnderstand: msg <Message> ^ <Object> = (
	^msg sendTo: contents 
)) : ()
class ResolvedFuture forwardingTo: f = Forwarder forwardingTo: f (
"A future in the resolved state. Must override all Object methods to be a true transparent forwarder."| 
	private dependents <List[UnresolvedFuture]> 
	"Tricky! This field is here to ensure that the shape of the resolved future is the same as an unresolved one.  It is not used in this class, but is referenced by the UnresolvedFuture code AFTER is has become an instance of this class. See UnresolvedFuture>>resolve"
	|)
('as yet unclassified'
resolve ^ <Object> = (
	^forwardee
)
resolved ^ <Boolean> = (
	^true
)) : ()
class UnresolvedFuture computing: c <[]> = (
"A local  pipelined promise in the unresolved state. Unlike a Delay, an UnresolvedFuture never resolves itself of its own accord. Its only response to messages is to create new futures for them (and register them as its dependents).  

Therefore, an UnresolvedFuture must be resolved explicitly from the outside. This causes it to  resolve itself recursively (so that any result, if it is a future, will also be resolved) and change its class to a ResolvedFuture (which is just a transparent forwarder). It will then also force the resolution of its dependents.

Unlike the promises exchanged between actors, futures accept synchronous messages.  They act as completely transparent proxies for future computations. This allows them to be used as the foundation of mutual recursion within a single sequential computation."|
	contents ::= c.
	dependents <List[UnresolvedFuture]> = List new.
|)
('as yet unclassified'
computation ^ <[]> = (
	^contents
)
doesNotUnderstand: msg <Message> ^ <Object> = (
	| pipelinedPromise <UnresolvedFuture>  |
	pipelinedPromise:: UnresolvedFuture 
		compute:[msg sendTo: self].
	dependents add: pipelinedPromise.
	"need to register piplelinedPromise so we can resolve it when self resolves"
	^pipelinedPromise
)
resolve ^ <Object> = (
	| r |
	r:: computation value.
	contents:: r isFuture ifTrue:[r resolve] ifFalse: [r].
	(ObjectMirror reflect: self) setClass: ResolvedFuture ifFail:[].
	dependents do:[:d <UnresolvedFuture> | d resolve].
	dependents:: nil.
	^contents
)
resolved ^ <Boolean> = (
	^false
)) : ()'as yet unclassified'
PipeliningFuture = (
	^self Future
)
SimpleFuture = (
	^self Delay
)) : ()