Feature #17355
openUsing same set of names in or-patterns (pattern matching with Foo(x) | Bar(x))
Description
Given pattern matching is officially supported in Ruby 3, I have an idea about making it more flexible.
Currently, this piece of code produces a syntax error
case [1, 2]
in [1, a] | [a, 3] => a then a
end # duplicated variable name
Duplications don't seem to be a problem here, semantically-wise. We just need to check if all patterns have the same set of names. It's supported in OCaml (also here's an RFC in Rust https://github.com/rust-lang/rust/issues/54883) so I think it can work in Ruby too.
I've been using pattern matching in Ruby since day 1 and it worked great so far. Since I use OCaml daily too I miss this feature every once in a while :)
A more practical example: imagine you have code like this
def user_email(user)
case user
in User(email:) then email
in Admin(email:) then email
in Moderator(email:) then email
end
end
Clearly, it could be simplified if or-patterns were supported:
def user_email(user)
case user
in User(email:) | Admin(email:) | Moderator(email:) then email
end
end
I'd like to know @ktsj's thoughts on this.
Updated by Dan0042 (Daniel DeLorme) over 1 year ago
Or-patterns are supported, just not with variable assignment. I agree with the request but the title of the ticket is a bit misleading.
But I think the user_email
example actually makes a rather good case for the usefulness of And-patterns:
def user_email(user)
case user
in (User | Admin | Moderator) & {email:} then email
end
end
Updated by decuplet (Nikita Shilnikov) over 1 year ago
- Subject changed from Or-patterns (pattern matching like Foo(x) | Bar(x)) to Using same set of names in or-patterns (pattern matching with Foo(x) | Bar(x))
Dan0042 (Daniel DeLorme) wrote in #note-1:
Or-patterns are supported, just not with variable assignment. I agree with the request but the title of the ticket is a bit misleading.
Yeah, thanks, I updated the title.
Dan0042 (Daniel DeLorme) wrote in #note-1:
But I think the
user_email
example actually makes a rather good case for the usefulness of And-patterns:def user_email(user) case user in (User | Admin | Moderator) & {email:} then email end end
Out of curiosity, did you see an example of syntax like that in any other language?
Updated by Dan0042 (Daniel DeLorme) over 1 year ago
decuplet (Nikita Shilnikov) wrote in #note-2:
Out of curiosity, did you see an example of syntax like that in any other language?
No I haven't. I briefly mentioned it in #16464#note-2; it just seemed a logical complement to Or-patterns (pun not intended)
Updated by ktsj (Kazuki Tsujimoto) over 1 year ago
- Assignee set to ktsj (Kazuki Tsujimoto)
- Status changed from Open to Assigned
I am pretty positive. I will discuss it with Matz after I finish to implement.
Updated by decuplet (Nikita Shilnikov) 10 months ago
It'd be nice to have this in 3.1 (no pushing).
Updated by duerst (Martin Dürst) 10 months ago
I'm confused by this code:
case [1, 2]
in [1, a] | [a, 3] => a then a
end # duplicated variable name
The variable isn't used twice, it's used four times. We can ignore the last one, because this is just to give a result back, and of course we should be able to give a back if we matched it.
But the third a
is very confusing. We match a
to 2 because [1, 2]
matches [1, a]
and not [a, 2]
, but then we match [1, a]
again to a
? It looks like an attempt to some kind of recursive unification, which is definitely not possible in Ruby.
So I would be okay to allow
case [1, 2]
in [1, a] | [a, 3] => b then a
end # duplicated variable name
or of course also
case [1, 2]
in [1, a] | [a, 3] => b then b
end # duplicated variable name
but anything that comes close to
in [1, a] | [a, 3] => a
seems confusing and dangerous.
Updated by decuplet (Nikita Shilnikov) 10 months ago
I'm confused by this code:
Actually, I'm too! The goal of this request doesn't go beyond having support for
case [1, 2]
in [1, a] | [a, 3] then a
end
The => a
is probably a leftover, I don't recall the reason I put it there, thank you for highlighting it.