Search code examples
promisesmalltalkpharo

Pharo promises:


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


Solution

  • 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