[ruby-core:117104] [Ruby master Feature#20318] Pattern matching `case ... in` support for triple-dot arguments
From:
"mame (Yusuke Endoh) via ruby-core" <ruby-core@...>
Date:
2024-03-12 03:29:17 UTC
List:
ruby-core #117104
Issue #20318 has been updated by mame (Yusuke Endoh).
I strongly feel "bad smell" for this proposal.
In principle, one method should do one thing.
But this syntax introduces a completly different branching depending on the arguments, which could encourage a weird method behavior.
In fact, the motivating example prints different messages depending on the arguments. I believe such a method would never be recommended.
In particular, the method that accepts `foo(str)` and `foo(greeting: str)` but not `foo(str, greeting: str)` looks rather weird to me. I am concerned that such a method could be so easily defined.
Considering the Java overloading, each overloaded method definition would often delegate to the most common (receives the most arguments) definition. Given that, the motivating example should be:
```ruby
def foo(...)
case ...
in args: [name]
puts "Hello #{ name }"
in args: [first_name, last_name]
foo(first_name + " " + last_name)
in kwargs: {greeting:}
foo(greeting)
else
raise ArgumentError
end
end
````
I do not find this code easy to understand.
As far as I know, Ruby has the most complicated argument system in the world. I don't think we should make it even more complicated.
----------------------------------------
Feature #20318: Pattern matching `case ... in` support for triple-dot arguments
https://bugs.ruby-lang.org/issues/20318#change-107177
* 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/