Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby method with a (*) signature

Tags:

ruby

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

like image 212
port5432 Avatar asked Dec 20 '25 23:12

port5432


1 Answers

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.

like image 124
Silvio Mayolo Avatar answered Dec 24 '25 09:12

Silvio Mayolo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!