Closed littledan closed 7 months ago
I don't think it would, because we have a need to use the already available and massive corpus of predicate functions.
Could you elaborate on that? I don't understand how you want to embed predicate functions and how this relates to let
.
Two important use-cases we want to ensure work as easily as reasonably possible are (1) matching against the value of an existing variable, and (2) matching using an existing predicate function (rather than requiring predicates to be specifically written against the pattern-matching model, using [Symbol.customMatcher]
/etc.
Both of these compete for the "plain ident" syntax space with bindings, and since we have the "well do you want let
or const
or var
" problem anyway, the easiest path forward is put bindings behind the declaration prefix, and let vars/preds use plain idents (along with custom matchers, which is how predicates are supported anyway (a built-in Symbol.customMatcher
property on Function.prototype
)).
(Technically, this collides these use-cases; you can't compare the subject with an object that has a custom matcher on it. In practice, this is pretty unimportant; comparing functions by object identity is a rare pattern. You can drop down to if()
patterns when it's actually required.)
It'd be great if someone could give an example of using a predicate function, showing how the syntax differs from matching against equality of a value that's in a variable.
const CR = 0x0d;
const LF = 0x0a;
function isWhiteSpace(ch) {...}
match(someChar) {
CR or LF: doSomething();
isWhiteSpace: doSomethingElse();
default: doAThirdThing();
}
Thanks for the example. Yes, I agree that these are important. Personally, I didn't mind the ${ }
syntax to handle that case, though I understand that the rest of the committee strongly disliked it. Another option is to have some particular kind of syntax for this case, of matching against a variable which is a predicate, or something to be compared for equality. For example, with the placeholder keyword kw
(since I don't have a good name in mind):
match(someChar) {
(kw CR) or (kw LF): doSomething();
kw isWhiteSpace: doSomethingElse();
default: doAThirdThing();
}
in this case, we have this (not as a group consensus but mentioned in the drafted spec):
match(someChar) {
(=== CR) or (=== LF): doSomething(); // "===" pattern
isWhiteSpace: doSomethingElse(); // custom matcher
default: doAThirdThing();
}
If I understand correctly where your current draft is (#313), then it looks like
let
is required to establish bindings within patterns. I definitely see how this is conceptually cleaner and more composable than earlier forms, though it's a bit syntactically heavy. Is this the champion group's current direction?My understanding is that
let
is important to subsume the need for${}
, which was a way to distinguish between what's establishing a new binding, and what refers to literals to be matched, extractors, or other things to be read from outside of the pattern.However, extractors show another path to distinguish between the pattern and the bindings--if it has parens after it, it's an extractor; otherwise it's a variable being assigned to. Would it work for pattern matching to apply the same mechanism here? This could be nice for consistency between forms as well as terseness, though it would reduce the other aspects of consistency which
let
introduces.