tc39 / proposal-extensions

Extensions proposal for ECMAScript
MIT License
150 stars 6 forks source link

Why $::util:toSet() equals to toSet($) but not toSet.cal($) in README "Example of using constructors or namespace object as extensions"? #9

Open LongTengDao opened 3 years ago

LongTengDao commented 3 years ago
// util.js
export const toSet = iterable => new Set(iterable)
import * as util from './util.js'
[]::util:toSet();// why here equals to `util.toSet([])`, but not `util.toSet.call([])`?

If so, why not use |> syntax instead?

In my opinion, value|>step1|>step2|>step3 syntax suits util that designed to use without other args, while value::step1(true)::step2()::step3('yes', 1) syntax suits util that designed to use with other args. The both proposals are mainly to avoid writting backward logic like step3(step2(step1(value))), but do chain thing like $(value).step1().step2().step3() more easily, free, and fast.

If :: want to cover the use cases that |> does, and |> want to cover the multiple arguments use cases which should leave to ::, the situation would be a mess...

hax commented 3 years ago

Extensions methods allow u chaining with normal methods in more ergonomics form. See https://johnhax.net/2020/tc39-nov-ext/slide#39

For example,

let classCount = document::allDivs
    ::flatMap(e => e.classList::toArray())
    ::toSet()::size

Any :: could be change to . (or vice versa) if there is real/extension methods u want to replace or insert. Changing to |> would ask many parens (because |> have very different operator precedence), and code reformatting. If not one and only one argument, there will be more codes to change (depending on which variant of pipeline u use and the pattern you adopt).

the situation would be a mess...

Basically, I believe extension methods/accessors have a simpler and consistent form with normal method call or property access, if your code is mainly oo-style or even multi-paradigm (like many code in the wild), this would be a better choice.

On the other hand, if your code is already fp-style (for example, use ramda or similar fp lib heavily), and rarely use oo-style, pipeline op may be better, though extensions-based value::pipe() could also be used instead of pipeline op.

cshaa commented 3 years ago

Why $::util:toSet() equals to toSet($) but not toSet.call($)?

@hax Looking at src/design.md, this is no longer the case, right? According to the current design, $::util:toSet() would be transpiled to something like:

util.prototype.toSet.call($)

Maybe it would be good to close this issue, so that it doesn't confuse newcomers (such as myself)?

LongTengDao commented 3 years ago

@m93a It's still in README:

https://github.com/tc39/proposal-extensions/blame/master/README.md#L64

hax commented 3 years ago

@m93a You miss the line in the design.md:

If O is not a constructor, x::O:func(...args) roughly equals to O.func(x, ...args).

Maybe I should make it much clear in the document.

cshaa commented 3 years ago

Oh, what a shame. I was hoping that this “syntax overloading” was dropped for a simpler and more consistent approach 😕️