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

wip object pattern matching #296

Merged
merged 7 commits into from
Jan 27, 2023
Merged

wip object pattern matching #296

merged 7 commits into from
Jan 27, 2023

Conversation

STRd6
Copy link
Contributor

@STRd6 STRd6 commented Jan 26, 2023

Pattern matching is getting closer.

@STRd6 STRd6 temporarily deployed to build January 26, 2023 03:46 — with GitHub Actions Inactive
@STRd6 STRd6 temporarily deployed to build January 26, 2023 20:56 — with GitHub Actions Inactive
@STRd6 STRd6 temporarily deployed to build January 27, 2023 00:04 — with GitHub Actions Inactive
@STRd6 STRd6 temporarily deployed to build January 27, 2023 19:50 — with GitHub Actions Inactive
Copy link
Collaborator

@edemaine edemaine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress!

As discussed in Discord, I think we should think about whether it's "right" that arrays are exact matching (require exact length instead of just "at least pattern's length") while objects are inexact matching (require at least these keys, but could have more). There are two parallels to draw:

  • TypeScript types: object types are inexact lower bounds (at least these keys are available), while arrays (as tuple patterns) are exact matches. This is what you're following now.
  • JS destructuring: both object types and arrays are inexact lower bounds. You can write [a, b] = [1, 2, 3].

The nice thing about exact patterns is that you can always build inexact patterns out of them using a rest parameter. Given that [a, b] forces array of length 2, you can use [a, b, ...] to ask for array of length at least 2. But there's currently no way to specify an exact object type. Possibly related to Flow's {| ... |} exact object type.

Exact object matching is a bit tricky to check — maybe add a test that Object.keys(obj) === n where n is the number of keys matched. It would definitely be useful for checking API call validity (e.g. Meteor check). I guess the question is whether it should be the default, and if you want inexact you add a ... rest; or if it should be "opt-in" via something like {| ... |}.

...prop,
children: [ws, ...prop.children],
}
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not important, but you could write this as follows (assuming we know length > 0 here?):

const [first, ...rest] = props
return [
  {...first, children: [ws, ...first.children]},
  ...rest
]

[/^foo$/, b]
console.log b
---
if(Array.isArray(x) && x.length === 2 && typeof x[0] === 'string' && /^foo$/.test(x[0])) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL that /5/.test(5) returns true. Probably checking that it's a string makes sense.

Idea for future: Once we have a way to assign parts to local variables, e.g. the pattern 5 as x, maybe we could do that for regex groups. E.g. /([+-])(\d+)/ as [match, sign, abs]

@STRd6
Copy link
Contributor Author

STRd6 commented Jan 27, 2023

I'm leaning towards TS semantics for the defaults. An opt-in exact match does sound useful in some situations and should be simple enough to add on later.

@edemaine
Copy link
Collaborator

Sounds good. I'm really looking forward to when I can write this:

interface point
  x: number
  y: string
switch v
  point
    ...
---
interface point {
  x: number
  y: string
}
if (typeof v === "object" && v != null && typeof(v.x) === "number" && typeof(v.y) === "string") {
  ...
}

Before we understand type references though (looking up point is tricky), I wonder if there's a way to specify "something of type number"? Maybe this (based on one of the #126 proposals):

switch v
  {x:: number, y:: string}

@STRd6
Copy link
Contributor Author

STRd6 commented Jan 27, 2023

I was thinking of something like:

switch v
  {x: <? "number", y: <? "string" }

making use of the expanded <?/instanceof

It would also allow thing like:

switch x
  <? Error
    ...
  <? Result
    ...

But that's slightly trickier to parse right now.

@STRd6 STRd6 temporarily deployed to build January 27, 2023 21:34 — with GitHub Actions Inactive
@STRd6 STRd6 merged commit 0293185 into main Jan 27, 2023
@STRd6 STRd6 deleted the pattern2 branch January 27, 2023 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants