On this interesting blog post about pattern matching, there is some code with a method signature of (*)
class Request < Data.define(:path, :scheme, :format)
def deconstruct_keys(*)
{ path: @path, scheme: @scheme, format: @format }
end
def deconstruct(*)
path.split("/").compact
end
end
This is different than
def a_method(*args)
I could not find any information in the Ruby docs.
What does def deconstruct_keys(*) mean?
Note This question was mentioned on Ruby Weekly
def a_method(*args)
...
end
Normally, when we write this, we get a list of all of the method's arguments stored in the args variable.
def a_method(*)
...
end
This is an anonymous form of the same. We accept any number of arguments but don't wish to give a name to that list variable. Now, we haven't given the list of arguments a name, but we can still splat it into another argument list. So while this isn't legal
def a_method(*)
# Should've just named it in the first place :(
args = *
...
end
this, on the other hand, is
def a_method(*)
another_method(*)
end
and will pass the arguments onto another_method. It's equivalent to
def a_method(*args)
another_method(*args)
end
The same can be done with Ruby 3 keyword arguments
def a_method(**)
another_method(**)
end
Note that, if your intention is to forward all arguments, you should use the ellipsis syntax.
def a_method(...)
another_method(...)
end
A lone * will act funny when delegating keyword arguments. For instance,
def foo(*args, **kwargs)
p args
p kwargs
end
def bar(*)
foo(*)
end
foo(1, a: 1) # Prints [1] then {:a=>1}
bar(1, a: 1) # Prints [1, {:a=>1}], then {}
When calling foo directly, named argument syntax gets passed to **kwargs, but when delegating through bar, it gets converted into a hash and then passed into *args. On top of that, * won't forward block arguments either, whereas ... is your general-purpose "pass all positional, named, and block arguments onward" catch-all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With