00:46
<rbuckton>
My preference was to drop it, I'm not sure where others stand
01:06
<TabAtkins>
aight, first draft is https://docs.google.com/presentation/d/1ckdNcRpzMB7oV91k98gNkXxVtwkzqIv0vALPffSaU44/edit?usp=sharing
01:06
<TabAtkins>
i'm assuming "no when"
01:12
<rkirsling>
new slogan: "no when, no how"
04:25
<ljharb>
my strong preference is to keep it
04:25
<ljharb>
explicit > implicit
04:25
<ljharb>
but for stage 2 i'm content saying "we'll decide to keep or drop the when prefix before stage 2.7"
04:26
<ljharb>
slide 4, undefined literal - null is always a literal, no exceptions, no matter what we decide
04:27
<ljharb>
oh oof, we decided not to make undefined and the non-finites special?
04:27
<ljharb>
when you say ident, let's say Identifier in backticks, to be explicit about the grammar production
04:28
<ljharb>
for slide 6, falsiness implying "no match" is fine, and a primitive truthy value implying "match" is fine, but an object should be the { matched: boolean, value: unknown } schema, yes?
04:29
<ljharb>
for slide 7, this is wrong - it needs to check for Object(3) - ie, boxed numbers - also, same for all primitive wrappers. typeof only detects primitives.
04:30
<ljharb>
slides 14 and 15 should reference caching, even though it's explained on slide 18
04:30
<ljharb>
globally, s/falsey/falsy
04:32
<ljharb>
i'd love more elaboration on slide 17 also
04:32
<ljharb>
overall, awesome, this is a great first draft :-)
04:44
<Jack Works>
i'm assuming "no when"
current spec is no when
04:44
<TabAtkins>
👍
04:44
<TabAtkins>
Examples in the readme are still all over, wasn't 100% sure
04:44
<TabAtkins>
I'll fix
04:47
<TabAtkins>
for slide 6, falsiness implying "no match" is fine, and a primitive truthy value implying "match" is fine, but an object should be the { matched: boolean, value: unknown } schema, yes?
Nah, remember we changed the model to let you tell which mode you're in (bool or arglist); in the bool mode it's just being a bool that matters, and in the list mode we expect a list but allow for bools
04:47
<ljharb>
hm, ok
04:49
<Jack Works>
slide 4, undefined literal - null is always a literal, no exceptions
currently in the spec, undefined is not a literal, it will find the "undefined" variable which might be shadowed. if we have concensus that this should not be like this, plz open an issue and I'll fix the spec
04:50
<ljharb>
originally we had undefined, Infinity, and NaN as "special", where they'd never be identifiers and always refer to the intuitive values
04:51
<Jack Works>

Any non-reserved ident sequence, with dots and/or square brackets.

We have a little bit more than that. this, MetaProperty, super and PrivateIdentifier can also involve this. (see PatternMatchingMemberExpression)

04:54
<Jack Works>

slide 6

Function is invoked with (subject, {matchType:“boolean”}).

it's f(subject, hint, receiver) right now. e.g. f(subject, "boolean", thisValue)

04:55
<Jack Works>
slide 7: actually we unbox boxed primitives (https://tc39.es/proposal-pattern-matching/#sec-number-%symbol.custommatcher% )
04:56
<Jack Works>
side 8: I think it's better to add hint, receiver to match the spec https://tc39.es/proposal-pattern-matching/#sec-function.prototype-%symbol.custommatcher%
05:06
<Jack Works>

If return value is true (not truthy!), same as returning [].

slide 16. we don't have this in the spec, and I think this behavior might be a footgun. if a function returns true, you should use it like f: .... Use it like f(...): ... is always an error

current in spec: https://tc39.es/proposal-pattern-matching/#sec-invoke-custom-matcher

05:10
<Jack Works>
I see the example of this in slide 17. it might be OK if it looks better, but still, it's not in the spec. please open an issue if we think this is OK and I'll add it into the spec.
16:20
<TabAtkins>
Oh, that's definitely been explicitly discussed in the past.
16:21
<TabAtkins>
But hm, I'm probably fine with restricting it.
17:10
<TabAtkins>
i'd love more elaboration on slide 17 also
What sort of elaboration are you thinking of? In the slide itself (there's not really much space) or just in speaker notes?
17:10
<ljharb>
like "matches" and "doesn't match", i'm pretty confused about why some of those are
17:44
<TabAtkins>
Okay, I've addressed all of the feedback.
17:45
<TabAtkins>
ljharb: I've rewritten slide 17 a decent bit, is it clearer or do you still want more details in the notes?
17:46
<TabAtkins>
Now let me go rewrite the README, it's so inconsistent with both itself and the spec text proposal
17:57
<ljharb>
so why does Option.Some match 5, but Option.some() does not?
17:58
<ljharb>
also, in the second example, what happens with Option.None(undefined)? is that different than Option.None()?
18:02
<TabAtkins>
Option.Some is doing a boolean check - per the impl, it just verifies the type is right (which is the expected pattern for most custom matchers in boolean context). Option.Some() is doing a list check - the impl returns a [s.v] array, and the arglist (equivalent to a [] matcher) doesn't match it.
18:04
<TabAtkins>
Similarly, Option.None(undefined) wouldn't match, because the impl returns a [] value, which doesn't match a [undefined] pattern.
19:41
<rbuckton>

Slide 4: use of - as separator in

0/+0/-0 only exception - 0 compares with SameValueZero

Is mildly confusing as it could be read as -0. I suggest changing this to an em-dash or using :

19:44
<rbuckton>
originally we had undefined, Infinity, and NaN as "special", where they'd never be identifiers and always refer to the intuitive values
I'm not a fan of changing scoping semantics to be out of line from the rest of the language as it breaks intuition in other ways and prevents host emulation (i.e., what if someone wants to create a Compartment that replaces the global Infinity or NaN in some fashion).
19:46
<ljharb>
aha ok thanks
19:46
<ljharb>
i think that's a weirdness of extractors then, that only adding () drastically changes the meaning of the pattern, but i suppose it's true in JS too
19:50
<rbuckton>
Not a weirdness, IMO. To extract you must have something to destructure and match against. foo is Bar() would expect the custom match result to yield zero elements, so true is not a reasonable result to match against.
19:54
<rbuckton>
TabAtkins: I'd recommend you move custom matcher slides closer to the end so that we don't end up stuck on that topic before we've provided context about the rest of the pattern syntax and matching behavior. If you want to reference how match (x) { Number: ... } works, I'd do it in a more hand-wavy way and just say that we'll come back to that later in the slides.
20:06
<rbuckton>

IMO, a good topic order for these slides might be:

  1. match syntax overview
  2. Literal constant patterns (i.e., "Primitive Patterns")
  3. Reference patterns (variable references and member references)
  4. Object patterns
  5. Array patterns
  6. Discards/void patterns
  7. Extractors
  8. Combinator patterns (and/or/not/parens)
  9. Variable declaration patterns (i.e., let/const/var) - calling them "Binding Patterns" is mildly confusing as JS already has something else called a binding pattern
  10. if patterns
  11. Semantics of custom matchers
  12. Future syntax

This order progressively builds in complexity while leveraging key information from previous slides. For example if patterns really need and to be meaningful. Oftentimes, so do let patterns.

20:09
<rbuckton>
On slide 20, you have match (Option.Some(5)) and match (Option.None()). Since you have defined these as class definitions, these examples would throw at runtime. They should read match (new Option.Some(5)) and match (new Option.None()). the latter of which is somewhat unfortunate since you only really want a singleton instance of None.
20:13
<rbuckton>
Also, the definition itself throws at runtime because you don't call super().
20:14
<TabAtkins>

IMO, a good topic order for these slides might be:

  1. match syntax overview
  2. Literal constant patterns (i.e., "Primitive Patterns")
  3. Reference patterns (variable references and member references)
  4. Object patterns
  5. Array patterns
  6. Discards/void patterns
  7. Extractors
  8. Combinator patterns (and/or/not/parens)
  9. Variable declaration patterns (i.e., let/const/var) - calling them "Binding Patterns" is mildly confusing as JS already has something else called a binding pattern
  10. if patterns
  11. Semantics of custom matchers
  12. Future syntax

This order progressively builds in complexity while leveraging key information from previous slides. For example if patterns really need and to be meaningful. Oftentimes, so do let patterns.

Makes sense, especially since the current custom matcher slides end up having to care about the extractor details too.
20:16
<TabAtkins>
Tho I think variable declarations needs to be earlier; I need them in several other examples. I think the use of combinators is obvious enough to use them ahead of time without comment.
20:20
<rbuckton>

Here's another way to write Option that lets you avoid having to write new in the match examples:

class Option {
    static #none = new this();
    #value;
    constructor(value) { this.#value = value; }
    static Some(value) { return new Option(value); }
    static None() { return Option.#none; }
    static {
        this.Some[Symbol.customMatcher] = function (s, hint) {
            if (s && #value in s && s !== Option.#none) {
                return hint === "boolean" ? true : [s.#value];
            }
            return false;
        };
        this.None[Symbol.customMatcher] = function (s, hint) {
            if (s === Option.#none) {
                return hint === "boolean" ? true : [];
            }
            return false;
        };
    }
}
20:29
<rbuckton>
I think you should rename the "Variable Patterns" slide. You're using "Variable" here while talking about an IdentifierReference, while I'd more equate "Variable" to let/const/var patterns
20:30
<rbuckton>
IMO, "Reference Patterns" is probably a more correct description for the audience since it involves multiple things that produce the Reference Record specification type (identifier references and property references)
20:42
<rbuckton>
In slide 17 you say "specified length", which might be conflated with array.length. I'd suggest you either use "same number of elements" and "match the corresponding elements" or something to the effect of "Matches if the sub-patterns match corresponding elements in the subject, with no more and no fewer elements".
20:45
<rbuckton>
In slide 18, you say "Not strict" but I think "Not exhaustive" might be better given that "strict" has other connotations in JS.
20:47
<rbuckton>
Also, as mentioned above, in slide 19 "Extractor Patterns", true is not the same as []. Honestly I'd rather a custom matcher throw if you use it as an extractor and it wasn't written to be used in that fashion.
20:49
<rbuckton>
On Slide 21 "Caching of Subject Parts", you have "Object patterns similar cache". I think you meant "similarly", but I would just remove the word altogether.
20:52
<rbuckton>
Makes sense, especially since the current custom matcher slides end up having to care about the extractor details too.
thinking about it, you mention combinators when talking about caching. It might be better to move combinators up before object and array patterns since you can use examples like "apple" or "banana" without needing to dig into other complexity.
20:56
<rbuckton>
For example, you can describe or simply with "apple" or "banana", not simply with not String, and and simply by building on not with String and not "apple"
21:00
<rbuckton>
We may also want to describe or, and, and not as "Disjunction", "Conjunction", and "Negation" patterns, but that's my personal preference.
21:00
<rbuckton>
And "Parentheses" as "Grouping Patterns"
21:01
<rbuckton>
Also, "Comparison Patterns" might be more aptly described as "Relational Patterns" as they mostly cover relational expressions and that is what is often used as the terminology in prior art.
21:07
<rbuckton>
In "Compact Object Pattern Cases", I'm not bullish on { a } meaning "equivalent to { a: void }" as that would break from how shorthand assignments work in object literals, assignment patterns, and binding patterns. One might expect { a } to mean { a: a }, just as { let a } means { a: let a }. It may not be convenient, but it would be consistent.
21:25
<ljharb>
I'm not a fan of changing scoping semantics to be out of line from the rest of the language as it breaks intuition in other ways and prevents host emulation (i.e., what if someone wants to create a Compartment that replaces the global Infinity or NaN in some fashion).
anybody who wants to change the meaning of those things is a bad person and should feel bad
21:26
<ljharb>
like i can't even conceive of a valid use case for it
21:28
<rbuckton>
Maybe so, but we still shouldn't break lexical scoping behavior for one feature, that just makes things more complex and a source of confusion for users. If its a bad enough problem that it needs fixing, we should find a way to fix it consistently.
21:28
<ljharb>
in general i'm in favor of consistency, but just like with coercion, and a number of other things, we shouldn't keep making new things bad just because we can't fix the existing badness
21:29
<ljharb>
it would make things more complex for engines and tooling, surely. but i do not believe it'd confuse anyone (the ability to redefine them is what's confusing)
21:30
<rbuckton>
This one seems like borrowing trouble. If no one is shadowing undefined, Infinity, and NaN today because its a bad practice, then fixing this here does nothing. If people are shadowing those things, then shame on them for doing that and we shouldn't go out of our way to fix it for that narrow case.
21:31
<rbuckton>
If they're shadowing for a reason, then don't break that reasoning. If they're shadowing by mistake, then they will likely have other problems besides match. Its just not worth borrowing trouble, IMO.
21:32
<ljharb>
it's not just about them tho
21:32
<ljharb>
basically every application runs third-party code. that code could mistakenly or intentionally redefine those things.
21:33
<rbuckton>
that's more of an argument for sandboxing and Compartment than it is for changing behavior here.
21:39
<rbuckton>
We could always investigate specifying undefined, Infinity, and NaN as immutable globals. No package that redeclares them with a value that isn't the original value is likely to be doing anything good. That would address the global concern, and third party code can't shadow a global in your own code, aside from eval.
21:40
<ljharb>
true