jedediah
jedediah

Reputation: 1219

Can this Ruby method call be made without **{} at the end?

I have a method defined like this:

def woot(a = nil, b: nil)
  ...
end

What is the least ugly way to pass a Hash instance to a when b is omitted?

I tried

woot(x: 1)
woot({x: 1})
h = {x: 1}
woot(h)

but they all raise

ArgumentError: unknown keyword: x

The only way to make the call that I have figured out is

woot({x: 1}, **{})

Is there a nicer way?

Upvotes: 5

Views: 111

Answers (2)

das-g
das-g

Reputation: 9994

If you don't expect b's default value to change, ever, how about passing it explicitly?

woot({x: 1}, b: nil)

Of course, if b's default value does change one day, you'd still be passing in nil, thus overriding the b value for that call to something else than its new default value.

Upvotes: 0

Karoly Horvath
Karoly Horvath

Reputation: 96258

Your first argument is optional, so Ruby assumes that the hash you're passing is for the named arguments (*).

I don't think there's a better workaround, though this is a bit shorter (but not necessarily cleaner):

woot({x: 1}, {})

If I were you I would change the method signature to resolve the ambiguity.


(*): Well, not always: woot({1=>3}) will happily pass the hash to the first optional argument.

Even weirder, in case of woot({1=> 5, :b => 4}), Ruby will split the dictionary, and pass {1=>5} to the first optional parameter.

Looks like it tries to grab the named parameters first (and will complain about not existing names), then pass the rest to the optional parameters.

But I would love to see some language-lawyer explanation...

Upvotes: 1

Related Questions