Re: Deprecating Future's .then()

On Saturday, May 18, 2013, Sean Hogan wrote:

>  After more consideration I think I have some proposed changes which make
> Futures more consistent and flexible without compromising the current
> compatibility with JS Promise implementations.
>
> PRIMARY CHANGE:
>
> The primary change is the addition of two methods - call them `thenfu` and
> `catchfu` for now - which become the preferred methods for registering
> callbacks.
>
> `thenfu` and `catchfu` are similar to `then` and `catch` in that they are
> called with "accept" and/or "reject" callbacks and that they return a new
> Future.
>
> But they are also similar to the Future constructor in that the associated
> resolver is available to the callback (via `this`) as the intended means of
> resolving the future.
>

Adding the resolver for the generated future was discussed here:

  https://github.com/slightlyoff/Futures/issues/46

The general consensus was that it can be added later if we like. I don't
see any need to expand the core contract for now.


> EXAMPLE:
>
> Using `thenfu` might look like this:
>
>     new Future(function() {
>         this.accept(2); // NOTE: `resolver` is `this`
>     })
>     .thenfu(function(value) { // immediate "accept"
>         this.accept(value * value); // NOTE: `resolver` is `this`
>     })
>     .then(function(value) { // same thing as previous `thenfu`
>         return value * value;
>     })
>     .thenfu(function(value) { // a delayed "accept" doesn't require
> another new Future
>         var r = this;
>         setTimeout(function() {
>             r.accept(value * 2);
>         });
>     })
>     .thenfu(function(value) { // Using `thenfu` with some JS Promise
>         var promise = getExternalPromiseDependingOnMyValue(value);
>         promise.then(this.accept, this.reject);
>     })
>     .thenfu(function(value) { // mapping async callback model to Futures
>         var r = this;
>         callAsyncFunction(value, function(err, result) {
>             if (err) r.reject(err);
>             else r.accept(result);
>         }
>     })
>     .done(function(value) {
>         console.log(value);
>     });
>
>
> BENEFITS:
>
> The main benefits of this addition are:
>
> a. consistency in the way futures are initialized and resolved - that is,
> resolving is always asynchronous via `resolver.accept|reject`.
>
> b. easily mix with non-Promise asynchronous code without creating yet
> another a new Future
>
> c. `then` doesn't need to be the feature-test for Promise objects,
> and doesn't need to be  a forbidden method of non-Promise objects.
>
>
> SECONDARY CHANGES:
>
> This addition necessitates and / or enables some secondary changes, most
> notably:
>
> a. the deprecation of `then` and `catch` from Future.
>
> b. the removal of `resolve` from FutureResolver.
>
> c. the modification of `new Future(init)` so that `resolver` becomes the
> `this` object of `init`.
>
> d. the requirement for `resolver.accept` and `resolver.reject` to be bound
> methods, thus enabling them to work when called as bare functions, for
> example:
>
>         jsPromise.then(resolver.accept);
>
> e. It is also necessary to modify `Future.any|every|some` to not rely on
> `then` detection.
> More on that in a future post.
>
>
> INTEROPERABILITY:
>
> The advice to JS libs and devs wanting to **mix DOM Futures and Promises**
> is:
>
> 1. `then` and `catch` are deprecated.
>
> 2. Future objects may be passed to code expecting Promise-like objects
> with a `then` method.
>
> 3. If you call a future's `then` or `catch` then your callback must return
> a Promise-like object - that is, an object with a compatible `then` method.
>
> 3. If you call a future's `thenfu` or `catchfu` then your callback must
> use the provided resolver and can accept or reject by any procedure.
>
>
> ASIDE:
>
> `then` and `catch` can be simply implemented on top of `thenfu` and
> `catchfu`. For example, some rough JS code for `catch` would look like:
>
>
>     Future.prototype.catch = function(onreject) { // NOTE: assume onreject
> is guaranteed a function
>         this.catchfu(function(value) {
>             try {
>                 var result = onreject(value);
>                 if (typeof result === 'object' && typeof result.then ===
> 'function') {
>                     result.then(this.accept, this.reject);
>                 }
>                 else this.accept(result);
>             }
>             catch(err) {
>                 this.reject(err);
>             }
>         });
>     }
>
>
> The reverse is also trivial, but requires the creation of a new Future and
> tying it to the one already created by `catch`.
>
>

Received on Wednesday, 5 June 2013 09:51:26 UTC