You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm running into a bug in promise.rb where the sync method breaks when mixing various Promise classes together.
Here's some sample code demonstrating the problem:
require"promise"classMyPromise < ::Promisedefwaitfulfill(456)endendp1=Promise.resolve(123)p2a=MyPromise.newp2a.syncp2b=MyPromise.newp3a=p1.then{ |a| p2a.then{ |b| a + b}}p3b=p1.then{ |a| p2b.then{ |b| a + b}}putsp3a.syncputsp3b.sync
What's happening is that when then is called on p1 (which is already resolved), promise.rb internally creates a new promise of the same type as p1 and then immediately executes the then block. Even though the then block is called immediately and returns a new MyPromise instance, the internal state of the promise returned by the then block is copied into the newly created Promise instance rather than the MyPromise instance being returned directly.
If p2a is also already resolved, this is not a problem and calling p3a.sync returns the right thing.
If p2b is not already resolved when p3b.sync is called, the sync call tries to call wait on an instance of Promise, rather than an instance of MyPromise. This raises a NoMethodError.
The output I'd expect the code sample above to produce is:
579
579
The actual output is:
579
lib/promise.rb:64:in `sync': undefined local variable or method `wait' for #<Promise:0x007fb8db51e028 @state=:pending, @callbacks=[]> (NameError)
from x.rb:20:in `<main>'
The text was updated successfully, but these errors were encountered:
Yes, that is the problem with mixing promise classes. This can be avoided by using p1 = MyPromise.resolve(123) so that you don't mix promise classes.
However, I don't think this is a bug.
To start with, you have an incorrect assumption that the block passed to then is executed immediately when the receiver Promise instance has already been resolved. The promise spec expects the onFulfilled or onRejected to be deferred. Promise#defer can be overridden to implement this behaviour and conform to the spec as documented in the README's usage section. This prevents the Promise#then method from being able to determine the class of a promise that may be returned from the block.
The other problem with what you are suggesting is that it would introduce racey behaviour in the type of value that is returned from Promise#then in code where the Promise instance could be resolved by another fiber or thread that is running in parallel. I would much prefer to have Promise#then deterministically return a result based on the type of the receiver so that it is easier to catch errors from misuse during testing.
I'm running into a bug in promise.rb where the
sync
method breaks when mixing various Promise classes together.Here's some sample code demonstrating the problem:
What's happening is that when
then
is called onp1
(which is already resolved), promise.rb internally creates a new promise of the same type asp1
and then immediately executes thethen
block. Even though thethen
block is called immediately and returns a newMyPromise
instance, the internal state of the promise returned by the then block is copied into the newly createdPromise
instance rather than theMyPromise
instance being returned directly.If
p2a
is also already resolved, this is not a problem and callingp3a.sync
returns the right thing.If
p2b
is not already resolved whenp3b.sync
is called, thesync
call tries to callwait
on an instance ofPromise
, rather than an instance ofMyPromise
. This raises a NoMethodError.The output I'd expect the code sample above to produce is:
The actual output is:
The text was updated successfully, but these errors were encountered: