From: "zverok (Victor Shepelev) via ruby-core" Date: 2024-03-01T08:20:21+00:00 Subject: [ruby-core:117026] [Ruby master Feature#20318] Pattern matching `case ... in` support for triple-dot arguments 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/