tc39 / proposal-iterator-helpers

Methods for working with iterators in ECMAScript

Home Page:https://tc39.es/proposal-iterator-helpers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Should "async" methods inherit from AsyncFunction.prototype, rather than Function.prototype?

bakkot opened this issue · comments

As suggested at tc39/ecma262#2942 (comment).

Fwiw web platform precedent does not do this; fetch.__proto__ === Function.prototype, for example.

I don't think that's a good precedent to follow; it's nice and consistent for a function that will always return a Promise and matches async function semantics to actually look like a userland async function.

Promise.all and friends also do not inherit from AsyncFunction.prototype, incidentally.

It seems to be a strictly editorial decision whether we specify a built-in as an async method or as a method that happens to always return a promise. Having it implicitly change the prototype just because of how we found it most convenient to spec the method seems pretty bad. That would make me lean toward not inheriting from AsyncFunction.prototype.

That said, you could make the same argument about ECMAScript functions and ECMAScript async functions...

So maybe the takeaway is that there's really no purpose for AsyncFunction.prototype? In that case, the decision really doesn't matter.

@bakkot that's primarily because they predate async functions, and nobody brought it up :-)

I completely agree that the normative and editorial decisions should not be coupled.

commented

I'd prefer to keep everything a plain function: whether a function will return a promise or not doesn't need to distinguishable from the outside in a dynamically typed language. This would encourage if (callback instanceof AsyncFunction) patterns, which we should not do.

However, if you wanted to do this, I'd couple the inheritance from AsyncFunction.prototype to whether or not Function.prototype.toString will return a string with async function syntax, i.e. Promise.all.toString() would then also have to return async function all() { [native code] }.

I definitely agree with the second part of your comment, regardless.

Decision from committee was to continue extending Function.prototype directly.

To preserve the thing I said in plenary: if async function had existed in ES6, then I would expect any builtin Promise-returning function to inherit from AsyncFunction.prototype. Since it didn't, there's virtually zero value in breaking consistency (and having some, but not all, builtin Promise-returning functions be AsyncFunctions) in order to have the imo "proper" inheritance chain.