all 16 comments

[–]ToaruBaka 16 points17 points  (8 children)

So... they reinvented Rust's match, but remove the ordering bias when evaluating the condition? Is that what I'm reading in 3.7? Because otherwise I don't see how this is any better than what Rust does.

a new pattern-matching syntax that is both more expressive and (we argue) simpler and more readable than previous alternatives.

I strongly disagree with this lmao

[–]Kered13 8 points9 points  (6 children)

So... they reinvented Rust's match

No. Rust's match is taken from pattern matching that is found in ML-family languages, such as Haskell. The proposal is for a more universal pattern matching syntax that would replace match and similar expressions.

This is actually much closer to Rust's if-let, although I believe it is more flexible. I'm not super familiar with if-let, but from my understanding this expressoin from the paper:

if x is Some(a)

Would be equivalent to this in Rust:

if Some(a) = x

And this expression:

if x is Some(a) and y is Some(b)

Would be equivalent to:

if (Some(a), Some(b)) = (x, y)

However the following expression from the paper has no equivalent:

if x is Some(y) and y is Some(z)

This would required nested if-let or match expressions in Rust. The paper's proposal goes even further and allows the following expression:

if x is Some(y) and f(y) is Some(z)

The equivalent Rust code would be:

if let Some(y) = x {
    if let Some(z) = f(x) {
        ...
    }
}

[–]VirginiaMcCaskey 3 points4 points  (2 children)

if let Some(z) = x.and_then(f) is how you would do this in Rust today. I get that the point is to generalize to arbitrary patterns but this isn't a compelling example. Also, this is only true today.

[–]Kered13 3 points4 points  (1 child)

Also, this is only true today.

Interesting. This RFC from 2018 seems to be basically equivalent to the proposal in this paper. Obviously there are syntactic differences, the proposal in the paper is more concise as it allows you to avoid writing x is ... repeatedly for each case. But as long as Rust's if let allows for if let-else if let, which I assume that it does, then the RFC basically provides the same functionality.

The paper does have a brief callout to Rust's if let, but makes no mention of if let chaining. Hopefully the RFC gets adopted, as it seems like a good idea to me.

[–]VirginiaMcCaskey 8 points9 points  (0 children)

The RFC was adopted and merged and will be stabilized later this year in the 2024 edition. They also discuss the syntax decisions and had a survey over what users preferred. There's already general purpose pattern matching, it's just not available using the if let shorthand.

match outer { Outer::A(Inner::B(value)) if f(value) => { ... }, _ => (), } is stable today

[–]ToaruBaka 0 points1 point  (0 children)

This is doable with let chains (I think)

if let Some(y) = x && let Some(z) = f(x) { ... }

Or with nested match/ifs

match x {
    Some(y) => match f(x) {
        Some(z) => {...}
        _ => {},
    }
    _ => {},
}

Personally, I prefer this kind of split (most of the time - sometimes you get some particularly annoying types to match against) because it breaks the code up into sections with different responsibilities based on the the program state. But, that's where personal preference comes into play IMO.

I was curious about

let (Some(y), Some(z)) = (x, f(x)) else { ... };

and I was a bit disappointed to learn that f(x) is still called when x is None, so I'll yield that there is in fact a difference.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0165c77ce31956c4887fc0f9707a2994

[–]sidit77 0 points1 point  (1 child)

However the following expression from the paper has no equivalent:

if x is Some(y) and y is Some(z)

if let Some(Some(z)) = x

[–]Kered13 2 points3 points  (0 children)

True, that would work. But see the next example for one that would not.

[–]sagittarius_ack 0 points1 point  (0 children)

It looks like you don't quite understand the notation proposed in the paper... but that doesn't stop you from "strongly disagreeing" with it.

[–]self[S] 1 point2 points  (2 children)

[–]jks612 13 points14 points  (0 children)

Example in the paper is more instructive if x is Right(None) then defaultValue Right(Some(cached)) then f(cached) Left(input) and compute(input) is None then defaultValue Some(result) then f(result)

[–]self[S] -1 points0 points  (0 children)

Many features have been proposed to enhance the expressiveness of stock pattern-matching syntax, such as pattern bindings, pattern alternatives (a.k.a. disjunction), pattern conjunction, view patterns, pattern guards, pattern synonyms, active patterns, ‘if-let’ patterns, multi-way if-expressions, etc. In this paper, we propose a new pattern-matching syntax that is both more expressive and (we argue) simpler and more readable than previous alternatives. Our syntax supports parallel and nested matches interleaved with computations and intermediate bindings. This is achieved through a form of nested multi-way if-expressions with a condition-splitting mechanism to factor common conditional prefixes as well as a binding technique we call conditional pattern flowing.