-
Notifications
You must be signed in to change notification settings - Fork 89
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
wip: sketching out idea in examples #140
Conversation
The examples don't include |
@noppa that's what I'm thinking it should do, yep. I'm not sure if |
One problem i have with this is, that the when-clauses aren't exactly destructuring. Making it look like the same would rather confuse people i think? Consider the example from the current readme: However, in destructuring the colon is used to assign a new name where |
That definitely seems to be the confusion for me - using const/let/var means it should work like destructuring, but destructuring only provides a facility to create bindings, not to match. |
I want to argue that the entire -premise- is to make everything look just like regular destructuring assignment, with a few extra rules for literal-matching that don't exist at all in regular destructuring. |
i like this! if there is confusion between destructuring and matching, is it too unsanitary (or impossible) to use the
|
That would directly conflict with default parameter syntax, which is supported by |
am i right in this:
and does that mean there's no way to do match against a scalar defined elsewhere:
without using the (i see now this isn't different from when there was |
That is correct. There's talk of a pin operator, the way Elixir does it, but that's a syntax grab I don't want to do. Note that other languages have this same behavior and expect guards for this use-case, such as Rust, and Elixir (unless you use an explicit pin ( |
console.log(`size is ${s}`), | ||
when {status: 404} -> { | ||
let {status: 404} -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let {status: 404} -> { | |
let {status: 404} -> |
I think this {
is a left over right?
I'm a big fan of this proposal. I'd say, merge it! This PR makes it more clear that we're creating an inner binding, and it reduces the number of keywords in the language. I think the analogy with destructuring is really important, but that's not because of the keyword |
But it's not the same, because destructuring works with any iterator, whereas pattern matching was supposed to work only with arrays... |
@phaux it does! The new version of the proposal operates on iterators, the same way destructuring does. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think this is a good idea; the confusion with variable assignments, including destructuring and defaults, isn’t worth it (unless I’m misunderstanding and they’re exactly the same).
I think the when
is an important signal at the start of the statement that this is a different thing - a pattern match.
@ljharb it works just like destructuring. The whole idea here is that if you know one, you know the others, and in that case, I do prefer the similarity. Also, would removing |
@zkat including default args? assuming so:
case (res) {
let {status: 200, headers: {'Content-Length': s}} ->
console.log(`size is ${s}`),
let {status: 404} -> {}
} would be a TDZ violation for declaring |
Fwiw as a lurker, I think the "oh, this works just like destructuring" is great in terms having a combined/single mental model across variable declaration/assignment and pattern match. I.e. if that was not the case, I could see users/new users constantly getting tripped up at "these [the destructuring syntax within const/let/when] look the same...but aren't..." That said, while I see the elegance of avoiding a new keyword, I'm tempted to think the I.e. it starts a new block, and whenever the next "when" happens means this "when" stops, which is also unlike let/const/etc, and I don't know that just the |
Using |
|
Looks really strange, aren't all bindings constant in pattern matching? |
As a lurker, going with |
I'm skeptical of |
Why would Matching against variables would be way more beneficial and "I am constructing a literal to match against" is a much simpler concept and easy to explain. The inclusion of the if statement is already a foreign feature straight out of elixir. |
@igl I don't understand what you want, current pattern matching makes sense, because it IS familiar to other languages |
For me there is too much differences to destructuring assignment that using let One case is the TDZ error mentioned by @ljharb above. Second case is that desctructuring of potentially Next, you probably don't want to support default values with pattern matching, because it will be confusing, people might want to try
Or even worse
Support for default values like this could break matching or lead to unreadable code. And there are probably more differences I could not find right now. So if we discuss, weather using |
Hol' up, this could be (ab)used to get optional destructuring 😅 tc39/proposal-optional-chaining#74 // Before
var bar = obj?.foo?.bar;
var baz = obj?.foo?.baz;
// After
case (obj) { var { foo: { bar, baz } } -> {} } I'm not sure if that's brilliant or terrifying. |
I think that was the point from the beginning const { bar, baz } = case (obj) {
when { foo: {bar, baz} } -> ({ bar, baz })
} |
@phaux Right, yeah, well that's better than the var-hack. when _ -> ({ bar: undefined, baz: undefined }) for the case where |
would all be valid forms |
In my opnion, it seems something like For example, the snippet mentioned above: case (res) {
let {status: 200, headers: {'Content-Length': s}} ->
console.log(`size is ${s}`),
let {status: 404} -> {}
} Seems like a pattern here: with (res) {
_.let(res, ({status, headers: {'Content-Length': s}}) => status === 200 && console.log(`size is ${s}`));
_.let(res, ({status}) => {});
} If considering short-circuits: with (res) {
// case 200
_.let(res, ({status, headers: {'Content-Length': s}}) => status === 200 && console.log(`size is ${s}`))
// other cases
&& _.let(res, ({status}) => {});
} |
The proposal has been significantly updated in #174; this PR seems no longer relevant, given that we've intentionally separated patterns from bindings. |
This is an initial sketch of an idea that came to mind tonight.
tl;dr: Instead of prefixing each clause with
when
, uselet
,const
, andvar
. I'm hoping that this achieves two things: 1. make it clear that these clauses use the same/similar destructuring rules as regular assignment; 2. it allows constants, lets, and vars so we know how the bindings are actually supposed to work.I'm almost certain someone has proposed something like this in the past, too, but I honestly don't remember where or when. I definitely know
const
bindings were requested in the past, though.Let me know what you think!