I worked on a promises project earlier this year in Pharo Smalltalk. The idea was to achieve the behavior below:
([ 30 seconds wait. 4 ]promiseValue )then: [ :a| Transcript crShow: a ].
This means that the promise will wait in the background for 30 seconds and print on the Transcript. This should not result in freezing of the Pharo user interface. My implementation below freezes the user interface. Why?
Class promise that implements Promises behavior:
Object subclass: #Promise
instanceVariableNames: 'promiseValue promiseError promiseLock'
classVariableNames: ''
package: 'META-Project-[pgakuo]'
Methods inside class Promise
doesNotUnderstand: aMessage
^ self value
perform: aMessage selector
withArguments: aMessage arguments
then: aBlock
promiseLock isSignaled
ifTrue: [ ^ self ].
promiseLock wait.
promiseError
ifNotNil: [ promiseError
privHandlerContext: thisContext;
signal ].
aBlock value: promiseValue.
self value: aBlock
then: aBlock catch: anotherBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseError ifNotNil: [ anotherBlock value: promiseError ].
promiseValue ifNotNil: [ aBlock value: promiseValue. self value: aBlock ]]
value
promiseLock isSignaled ifFalse: [ promiseLock wait ].
promiseError ifNotNil:
[ promiseError
privHandlerContext: thisContext;
signal ].
^promiseValue
value: aBlock
promiseLock := Semaphore new.
[
[[promiseValue := aBlock value]
on: Error do: [:err | promiseError := err]]
ensure: [promiseLock signal]] fork
And one method added to Blockclosure to make closures use the Promise behavior.
promiseValue
^ Promise new value: self
A block is passed to an instance of Promise and it is executed by Promise>>value: which uses fork to perform tasks in the background. But it does not seem to be working as desired
I solved the freezing problem as follows:
then: aBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseValue ifNotNil: [ aBlock value: promiseValue ]] fork.
And the below code on playground does not freeze the UI
[ 12 seconds wait. 12 ]promiseValue then: [ :a| Transcript crShow: a/2 ]
it prints 6 after 12 seconds of not freezing the UI