-
Notifications
You must be signed in to change notification settings - Fork 35
Future #432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Future #432
Conversation
|
ping @nechaido |
| } | ||
| }) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this perhaps be rewritten without double Future?
map(fn) {
return new Future((resolve, reject) => {
this.run(value => {
try {
resolve(fn(value));
} catch (error) {
reject(error);
}
});
});There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bringing the attention here!
I was able to spot the inconsistency of error handling.
The ideologically correct way to implement map function for any monad is the application of chain to the composition of of and fn. Rambda did it.
To do it here one simply needs to move error checking from here to run method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation of map through already existed chain and of is less efficient because of the creation of two Futures. That said such implementation reuses code and is the same for any monad. Though the duplicated code here is tiny meaning it may be allowed here for clarity.
So there is a tradeoff between performance and ideological purity here :-)
|
|
||
| promise() { | ||
| return new Promise((resolve, reject) => { | ||
| this.run(value => resolve(value), error => reject(error)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.run(value => resolve(value), error => reject(error)); | |
| this.run(value => resolve(value), reject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the lambda is used for dropping other arguments
|
|
||
| chain(fn) { | ||
| return new Future((resolve, reject) => | ||
| this.run(value => fn(value).run(resolve, reject), error => reject(error)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.run(value => fn(value).run(resolve, reject), error => reject(error)) | |
| this.run(value => fn(value).run(resolve, reject), reject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| const { Future, futurify } = require('..'); | ||
| const metatests = require('metatests'); | ||
|
|
||
| metatests.test('Future map/run', async test => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| metatests.test('Future map/run', async test => { | |
| metatests.test('Future map/run', test => { |
?
(and in other tests)
|
|
||
| metatests.test('Future stateless', async test => { | ||
| const f1 = Future.of(3); | ||
| const f2 = f1.map(x => ++x); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const f2 = f1.map(x => ++x); | |
| const f2 = f1.map(x => x + 1); |
| .map(() => { | ||
| throw new Error('msg'); | ||
| }) | ||
| .run(test.mustNotCall, error => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| .run(test.mustNotCall, error => { | |
| .run(test.mustNotCall(), error => { |
| } | ||
| }) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bringing the attention here!
I was able to spot the inconsistency of error handling.
The ideologically correct way to implement map function for any monad is the application of chain to the composition of of and fn. Rambda did it.
To do it here one simply needs to move error checking from here to run method.
| } | ||
|
|
||
| run(successed, failed) { | ||
| this.executor(successed, failed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's important to catch errors the executor may throw. It will also allow omitting error handling in the map method
| } | ||
| }) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation of map through already existed chain and of is less efficient because of the creation of two Futures. That said such implementation reuses code and is the same for any monad. Though the duplicated code here is tiny meaning it may be allowed here for clarity.
So there is a tradeoff between performance and ideological purity here :-)
Closes: #431