Open legendecas opened 2 years ago
@legendecas: Thanks for raising this! @hax (the champion of Extensions) and I have indeed been discussing privately, since August, about ways to reconcile our two proposals. (See also my detailed comparison document.)
I think it would be a great idea for us to continue those discussions publicly in this issue, though.
(@hax has said that their free time will be scarce over the next several months, which I will definitely try to respect with regards to advancing this proposal. ^_^)
The major differences seem to be the namespace, extraction, and special affordance for getters/setters. The former has strong pushback, the middle doesn't seem to have compelling motivation yet, and the latter doesn't seem to warrant special treatment (this is a combo of my opinion and my estimation of committee temperature).
Are there other differences I've missed?
@hax has said that they are open to dropping the special namespace (not sure about the special polymorphic extraction/calling syntaxes)âitâs the special treatment of getters/setters thatâs the crux, perhaps.
i hope this make sense
import {map} from 'somewhere';
document.querySelectorAll('div')
|> []:filter(%, v => v.clientWidth > 200) // : to unThis
:: []:filter(v => v.clientHeight > 200) // :: as alternative |> and %, RHS should be function and prepend LHS as first param
|> :map(%, v => (v.style.color="red", v)) // : to unThis
:: :map(v => (v.style.backgroundColor="green", v))
// or using prototype
document.querySelectorAll('div')
|> Array.prototype:filter(%, v => v.clientWidth > 200) // : to unThis
:: Array.prototype:filter(v => v.clientHeight > 200) // :: as alternative |> and %, RHS should be function and prepend LHS as first param
// maybe an alternate option can be
document.querySelectorAll('div')
|> Array.prototype:filter(%, v => v.style.color === "red") // : to unThis
|> Array::filter(%, v => v.clientWidth > 200) // :: as shortcut for [CLASS].prototype:[METHOD]
:> Array::filter(v => v.clientHeight > 200) // :> as alternative |> and %, RHS should be function and prepend LHS as first param
:> :map(v => (v.style.backgroundColor="green", v))
in this way we can also divide this proposal in three operators : (unThis) :: (unThis from prototype) :> to prepend LHS value in RHS parameters
Thanks for the comment, although it doesnât seem to be related to the extensions proposal (the original topic of this issue).
Iâm going to mark both of our comments as off-topic. You could open a new issue about this idea. ^_^
(For what itâs worth, TC39 is trying to minimize the number of operators that get added to the language, so it is unlikely that TC39 would add three new operators in addition to the Hack pipe operator. In addition, an unThis operator would lose the natural word order that a bind operator would restore. So I donât think we would pursue your idea anywayâthanks anyway, though!)
As the extensions section (and the in-depth comparison) say, the concrete differences between bind-this and extensions are currently:
const ::{ ⊠} from âŠ;
syntax.âŠ::âŠ:âŠ
syntax.Symbol.extension
metaprogramming system.@hax is willing to drop the first difference, but Iâm not yet sure whether he would be willing to drop anything else from the list above. But I plan to keep engaging with him over the next few months, time permitting.
An update: I, @tabatkins, and @hax recently wrote articles about the dataflow proposals, including bind-this and Extensions, and TC39 also held two two meetings about the dataflow proposals:
We will discuss the two proposals further at the next plenary at the end of this month.
Note, as the recent change from bind-this to call-this, the semantic of this proposal is now the subset of extensions proposal, and the syntax of this proposal also could be compatible with extensions proposal, if we choose "receiver-first style (bracketed)" like rec::[fn](arg0)
. ( ::
is bikeshed, if we choose ->
, it would be rec->[fn](arg0)
. )
I must say I really dislike the bracketed syntax. Using parenthesis (rec::(getFn())(arg0)
) should be allowed, but not required for identifiers (rec::fn(arg0)
) and member expressions (rec::namespace.fn(arg0)
, rec::namespace["fn"](arg0)
).
@bergus As extensions proposal, it also have rec::method()
syntax so the pair of rec::method()
and rec::[method]()
is actually mapping the rec.method()
and rec[method]()
syntax.
@hax Are you referring to this thing? I don't quite understand why rec::[method]()
uses bracket syntax - it doesn't appear to evaluate method
to a property name. I think it would make sense in rec::namespace:[nameExpr](...args)
, desugaring to Call(GetOwnProperty(namespace, nameExpr).value, rec, args)
(or GetExtension
instead of GetOwnProperty
), but not without a namespace object in which the property name is resolved (since we don't want to resolve it on the receiver).
@bergus Yes. v::ns:[expr]
is also possible, or required if we have strong symbol use cases (see https://github.com/tc39/proposal-extensions/issues/11).
Syntax rec::method / rec::[method]
choose []
is just for matching v.method / v[method]
. But you are right, rec::[method]
doesn't evaluate method
to key but evaluate method
to the method (or accessor) directly.
Of coz, we could consider other brackets syntax if we want to keep [x]
alway mean evaluating key: rec::(method)
, rec::{method}
, rec::${method}
(pattern match proposal use syntax like that) or even rec::<method>
(turbofish! đ ), it's just like the current escape hatch syntax of decorators @(decorator)
.
Syntax
rec::method / rec::[method]
choose[]
is just for matchingv.method / v[method]
. But you are right,rec::[method]
doesn't evaluatemethod
to key but evaluatemethod
to the method (or accessor) directly.
(For what itâs worth, I actually see some value in an analogy of bound functions acting as pseudo-âmethodsâ of their objects, with the original functions acting as pseudo-âkeysâ. For example, in rec::fn()
, the fn
would be acting like a âkeyâ on the âmethodâ rec::fn
, before being called.
However, I got some pushback from some others in the Committee about this analogy, so I dropped my pushing it.)
@js-choi I think the problem may be "bound" is unrelated semantic (of method), and I'm not sure the pushback is because such analogy, my impression is some delegates don't like "free" method. Actually I also feel "free" methods are not common in JS ecosystem, this is why extensions have a special syntax constraints to make it not as "free" as normal functions, one of my design goal is to make the extension users can only use extension methods as "method", not "function" by default.
Congratulations on stage 1! đ
First of all, I'm strongly supportive of the bind operator things, it is a very good supplementary to the language. Both this proposal and extension proposal has a very similar motivation and similar design, similar semantics on the
::
operator. @hax mentioned that the parallel namespace is not an essential part of the extension proposal and can be removed under the temperature of the committee. And the significant difference between the two proposals is the semantics of binding accessors. I'm wondering if it is better for two proposals to collaborate and find a consensus?