[ruby-core:117026] [Ruby master Feature#20318] Pattern matching `case ... in` support for triple-dot arguments
From:
"zverok (Victor Shepelev) via ruby-core" <ruby-core@...>
Date:
2024-03-01 08:20:21 UTC
List:
ruby-core #117026
Issue #20318 has been updated by zverok (Victor Shepelev).
@ko1 The pretty similar effect can be achieved by combining several recent features:
```ruby
def foo(*, **) = case [*, **]
in name, {}
puts name
in first_name, last_name, {}
puts "Hi there #{first_name} #{last_name}"
in [{greeting:}]
puts "Hello #{greeting}"
in *args
puts "No match: #{args}"
end
foo('ko1') #=> "ko1"
foo('ko1', 'ssd') #=> "Hi there ko1 ssd"
foo(greeting: 'hello') #=> Hello hello
foo('ko1', 'ssd', greeting: 'hello') #=> No match: ["ko1", "ssd", {:greeting=>"hello"}]
```
On the plus sides:
* it doesn't require any new constructs but cleverly combines existing ones (that also can be combined in different ways, so it is insightful): e.g. `def foo(args) = statement` can become a popular idiom to emphasize one-statement methods,;
* many of things are still explicit, if short: no special names, like `*args` is what you write there; a flexibility of applying this approach to either positional-only, or keyword-only, or both-arg-types methods (`*`/`**` can combined any necessary way);
The drawbacks here are:
* some things that feel unnecessary in this case (both positional and keyword args), like "don't forget empty `{}` at the end" or necessity to wrap `{greetings:}` in `[]`
For methods that have only positional, or only keyword args, it would be a bit clearer:
```ruby
def index(*) = case [*]
in [Integer => index]
p(index:)
in [Integer => from, Integer => to]
p(range: from..to)
in [Range => range]
p(range:)
end
index(1) #=> {:index=>1}
index(2, 3) #=> {:range=>2..3}
index(4..5) #=> {:range=>4..5}
def hey(**) = case {**}
in {rank:, **}
puts "Salute, #{rank}"
in first:, last:
puts "Good day, #{first}, #{last}"
in first:
puts "Hey, #{first}"
end
hey(first: 'John') #=> "Hey, John"
hey(first: 'John', last: 'Smith') #=> "Good day, John Smith"
hey(rank: 'Major', first: 'John', last: 'Smith') #=> "Salute, Major"
```
It seem to look reasonably close to method reloading, but still has its quirks.
----------------------------------------
Feature #20318: Pattern matching `case ... in` support for triple-dot arguments
https://bugs.ruby-lang.org/issues/20318#change-107094
* Author: bradgessler (Brad Gessler)
* Status: Open
----------------------------------------
# Premise
Sometimes when I'm creating a method for an API, I'd like to do pattern matching against the arguments. Today I have to do something like this:
```ruby
def foo(*args, **kwargs, &block)
case { args:, kwargs:, block: }
in args: [name]
puts name
in args: [first_name, last_name]
puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
puts "Hello #{greeting}"
else
puts "No match: #{args}"
end
end
foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```
Or an array like this:
```ruby
def bar(*args, **kwargs, &block)
case [args, kwargs, block]
in [name], {}, nil
puts name
in [first_name, last_name], {}, nil
puts "Hi there #{first_name} #{last_name}"
in [], {greeting:}, nil
puts "Hello #{greeting}"
else
puts "No match: #{args}, #{kwargs}"
end
end
bar "Howdy"
bar "Bradley", "Gessler"
bar greeting: "Bradley"
```
# Proposal
I'd like to propose the same thing, but for `...`, like this:
```ruby
def foo(...)
case ...
in args: [name]
puts name
in args: [first_name, last_name]
puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
puts "Hello #{greeting}"
else
puts "No match: #{args}"
end
end
foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```
One thing I'm not sure sure about: the `args`, `kwargs`, and `block` names appear out of thin air, so ideally those could somehow be named or have a syntax that doesn't require those names.
The array would look like this:
```ruby
def bar(...)
case ...
in [name], {}, nil
puts name
in [first_name, last_name], {}, nil
puts "Hi there #{first_name} #{last_name}"
in [], {greeting:}, nil
puts "Hello #{greeting}"
else
puts "No match: #{args}, #{kwargs}"
end
end
bar "Howdy"
bar "Bradley", "Gessler"
bar greeting: "Bradley"
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/