Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interoperability with symbol-based protocols #4

Closed
js-choi opened this issue Sep 20, 2021 · 11 comments
Closed

Interoperability with symbol-based protocols #4

js-choi opened this issue Sep 20, 2021 · 11 comments
Labels
documentation Improvements or additions to documentation question Further information is requested

Comments

@js-choi
Copy link
Collaborator

js-choi commented Sep 20, 2021

In tc39/proposal-extensions#11, @bmeck wrote the following:

i think the bind operator changes the general flow and are bigger refactors from normal JS workflows and don't necessarily have the path towards dealing with protocols that [the Extensions] proposal does.

other bind proposals take an expression and bind the values within that expression. [The Extensions] proposal allows dispatch to match the normal receiver of an expression during invocation using a value not on the receiver. Other bind proposals do not allow lexical receivers in normal JS position and instead use currying.

Because this repository is meant as a simplified successor to the old bind-operator proposal and as an alternative to tc39/proposal-extensions, I opened an issue here.

Having said that, I am not quite sure I understand the quoted concerns. This proposal works with symbol-based protocols. And, in this proposal, no arguments (other than the this value) are bound.

Either of these would simply work:

y->(Array.prototype[Symbol.iterator])();
const $arrayIteratorFn = Array.prototype[Symbol.iterator];
y->$arrayIteratorFn();

CC: @ljharb

@js-choi js-choi changed the title Interoperability with protocols Interoperability with symbol-based protocols Sep 20, 2021
@js-choi js-choi added documentation Improvements or additions to documentation question Further information is requested labels Sep 20, 2021
@bmeck
Copy link
Member

bmeck commented Sep 20, 2021

It would be good to understand how this proposal works on the following example:

for (let key of map.keys()) {
}

Right now it looks like it would be rewritten using this proposals as

for (let key of {[Symbol.iterator]: map->(Map.prototype.keys)}) {

}

This in turn exposes the mutable Map Iterator instance that doesn't really have a way to protect against .next mutation. E.G.

// stops the loops
Object.getPrototypeOf(new Map().entries()).next = function () {return {done: true, value: 'hi'};};
const myMap = new Map([[1,1],[2,2]]);
for (const x of myMap) {
  console.log({x})
}
for (const x of myMap) {
  console.log({x})
}
for (const x of myMap) {
  console.log({x})
}

I do agree for functional approaches that this proposal does enhance the ability to write robust code but it seems difficult / unlikely to actually protect against OO robustness and could lead to confusion.

@ljharb
Copy link
Member

ljharb commented Sep 21, 2021

Yes, due to the design of MapIterator this proposal doesn't address it directly.

However, you could do const mapKeys = new Map().keys()[Symbol.iterator]; map→keys()→mapKeys() just fine, so i'm not sure what the concern is.

@bmeck
Copy link
Member

bmeck commented Sep 21, 2021

That would still fail to execute the loops. I'm stating that this proposal should be wary of OO patterns which are often off of Symbol protocols since it does cause problems. These OO problems are much harder to mitigate than the existing bind pattern. I'm unclear a bit on the claims of robustness holding up as a goal if it leads to pitfalls like this. The issue was about problems, which still exists. Wether it is in scope or not is not really easy to discern without going to plenary, but I would state at least from the readme this is a concern given that it gives a false sense of robustness.

@ljharb
Copy link
Member

ljharb commented Sep 21, 2021

Aside from Symbol.iterator, Symbol protocols are hardly ever used - but I’m still very confused here. Symbols and strings are identical.

I see how it gets tricky if the code you’re writing uses one method access (string or symbol) to produce a new object, on which you then do another method access (string or symbol) - but that’s the same problem no matter what kind of property key is used.

@bmeck
Copy link
Member

bmeck commented Sep 21, 2021

Maybe we can just rename this to interoperability with OO based protocols?

@ljharb
Copy link
Member

ljharb commented Sep 21, 2021

It’s not just OO-based tho - that’s what Array slice is. It’s the specific pattern of one method in an X returning a new kind of object Y, which then needs its own methods saved with this operator.

This is a rare pattern other than the builtin iterator types, but again, for those, i think you could still do the same things - it’s just trickier to get at them since they’re not globals in the first place. Luckily there’s another proposal for getting intrinsics :-p

@bmeck
Copy link
Member

bmeck commented Sep 21, 2021

Perhaps interoperability with things that return Objects?

@ljharb
Copy link
Member

ljharb commented Sep 21, 2021

Much better, but it’s even a tiny subset of that - things that return objects that aren’t directly accessible (globally, or importable/requireable).

@bmeck
Copy link
Member

bmeck commented Sep 21, 2021

@ljharb I don't think indirect access is necessary since Map.prototype for example is directly accessible and since this proposal predicates early access anyway you can just call it eagerly to get the stuff.

@ljharb
Copy link
Member

ljharb commented Sep 21, 2021

Right but there’s no ergonomics issue with Map.prototype - only with, eg, MapIterator.prototype, unless I’m misunderstanding something. (this all ofc assumes first-run code)

@js-choi
Copy link
Collaborator Author

js-choi commented Oct 6, 2021

I’m going to close this problem as out of scope. Although improving the Node primordials situation is one of the goals of this proposal, I’ve refocused its greater thrust onto “bind/call/apply are very common but they are clunky” (#8). This problem seems to be pretty rare even within the primordials use case, anyway. Let me know if there’s anything else actionable that we can do here.

@js-choi js-choi closed this as completed Oct 6, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
documentation Improvements or additions to documentation question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants