tc39 / proposal-pattern-matching

Pattern matching syntax for ECMAScript
https://tc39.es/proposal-pattern-matching/
MIT License
5.5k stars 89 forks source link

Allow binding variables inside match #238

Closed ByteEater-pl closed 2 years ago

ByteEater-pl commented 2 years ago

No other language I know with pattern matching supports this, but I'd have used it on a number of occasions: a const among the clauses, evaluated only if none of the preceding clauses matched, defining variables in a scope encompassing the remaining clauses. It can be achieved with nesting match, but awkwardly, requiring repeating the scrutinee (called matchable in this proposal – btw, did you consider changing that name?) and other shenanigans.

ljharb commented 2 years ago

I'm not sure what you're asking about. Can you provide example code?

("matchable" is a fine name; there's no real reason to change it imo)

ByteEater-pl commented 2 years ago
long_expression match {
    when (pattern1) result1
    when (pattern2) result2
    const comma_separated_assignments
    when (pattern3) if (condition) result3
    else result4
}

The variables assigned in comma_separated_assignments are available in result3, result4, condition, as well as in interpolated parts inside pattern3.

ljharb commented 2 years ago

Why? Do you have a concrete use case for that?

tabatkins commented 2 years ago

@ByteEater-pl ping? Any concrete examples showing off the desired functionality?

ByteEater-pl commented 2 years ago

Let's say reading an entity with the read function should be avoided unless necessary.

result = operation_to_interpret match {
    when (["const", x]) x
    const entity = read()
    when (["data", x]) entity[x]
    when (["metadata", x]) entity.meta[x]
    when (_) (() => { throw Error() })()
}
mpcsh commented 2 years ago

Why not just write

const entity = read();

result = match { ... };

?

ljharb commented 2 years ago

or, if it's expensive:

result = operation_to_interpret match {
    when (["const", x]) x
    default match (read() as entity) {
      when (["data", x]) entity[x]
      when (["metadata", x]) entity.meta[x]
      when (_) (() => { throw Error() })()
    }
}
mpcsh commented 2 years ago

@ljharb I don't think that would do what @ByteEater-pl wants, because a the clauses are supposed to match on the top-level matchable, but the three inside your nested match are actually matching on entity.

EDIT: that said, I still really don't see a concrete use-case for this here. @ByteEater-pl, do you have a real-world (i.e., not contrived) use-case?

ByteEater-pl commented 2 years ago

@mpcsh, I did, a number of times IIRC, that's why I opened this issue. But I don't remember what I was writing and where to find it. Maybe it'll come back to me or I'll come across another good example. So if you decide to close this issue for lack of sufficient use cases, please leave the ability to comment to allow providing them and reopening when appropriate.

mpcsh commented 2 years ago

Yeah, I'm going to go ahead and close this, but if you find a compelling use-case feel free to reopen. Thanks :)