Promise.cast and Promise.resolve

Paolo Amadini paolo.02.prg at amadzone.org
Tue Jan 28 04:24:57 PST 2014


I have a suggestion about the current draft of the Promises
specification that derives from my experience on the Mozilla code base.
I'm not familiar with how the specification process works, discussion
in this group seemed like a good start.

Those familiar with the subject may find that this topic has already
been discussed (see [1] and [2]), but I think I may provide some
additional data that has not been previously examined, at least
according to the discussions that I found online, and may help in
determining the final direction.

In our code base, historically we only defined the "Promise.resolve"
function. I had a look at its 490 uses:
http://mxr.mozilla.org/mozilla-central/search?string=Promise.resolve

It looks like 487 of them don't have a promise as an argument, in which
case "cast" and "resolve" would behave in exactly the same way.

In the remaining cases (namely Task.jsm and AsyncShutdown.jsm) I
suspect we would always use either "resolve" (to be safe) or "cast"
(to be more efficient), and I'd lean for "cast" since we'd like Task
iterations to be faster. It also appears that "cast" has been selected
as the implicit conversion for Promise.all([valueOrPromise]) and
Promise.race([valueOrPromise]), maybe for the same efficiency reason.

Moreover, only after I read Domenic's comment [3] I realized that,
despite the name, the function that makes _less_ guarantees about the
returned object is "cast", and "resolve" actually made more guarantees.

So, if you're really interested in casting an "unsafe" promise to the
type of your promise library, it's theoretically better to use
"resolve" than "cast". By "unsafe" I mean a promise created internally
that may have been modified. In the case of "foreign" promises from
other libraries, using "cast" and "resolve" is again exactly the same
thing.

My take is that the difference between "cast" and "resolve" is so
subtle that I don't think it captures developer intention. In
other words, if I see some code calling Promise.cast(otherPromise),
I can't be sure that the developer made an intentional choice over
Promise.resolve(otherPromise).

In the case of non-promises, where the behavior is really identical,
I expect that, with both functions available, by now in the Mozilla
code base we would have about 50% calls to "cast" and 50% calls to
"resolve". This, unless we spent time in defining a guideline for one
function or the other, with the associated education costs.

Assuming we succeeded in defining the guideline of always using "cast"
for non-promises, we'd have 490 calls to "cast" and no calls to
"resolve" at all. I also don't see a real-world use case for "resolve"
in the future. In case we needed to be really sure about the object
we're handling (that I don't think will be needed), I think we could
always use "new Promise(r => r(otherPromise))" instead.

My conclusion is that the "resolve" function could be removed.

Optionally, "cast" could be renamed to "resolve". It has in fact been
mentioned in [2] that some promise libraries already implement an
optimized "resolve", that works mostly like "cast". Against this
suggestion, there were concerns about the length of the name and
establishing a precedent for the name "cast".

I don't think the name is really important, but I'd rather not have
two almost identical functions to be chosen that will require a style
guideline and maybe another lint tool check to be defined in addition
to the ones that JavaScript already requires.

What do you think?

Regards,
Paolo

[1] https://github.com/domenic/promises-unwrapping/issues/86
[2] https://github.com/domenic/promises-unwrapping/issues/8
[3]
https://github.com/domenic/promises-unwrapping/issues/86#issuecomment-30066102


More information about the es-discuss mailing list