Read more

Ruby: Do not mix optional and keyword arguments

Tobias Kraze
September 30, 2015Software engineer at makandra GmbH

Writing ruby methods that accept both optional and keyword arguments is dangerous and should be avoided. This confusing behavior will be deprecated in Ruby 2.7 and removed in Ruby 3, but right now you need to know about the following caveats.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

Consider the following method

# DO NOT DO THIS

def colored_p(object = nil, color: 'red')
  switch_color_to(color)
  puts object.inspect
end


colored_p(['an array'])                   # ['an array'] (in red)
colored_p({ a: 'hash' }, color: 'blue')   # {:a=>'hash'} (in blue)
colored_p({ a: 'hash' })                  # ArgumentError: unknown keyword: a

What happened?

Ruby does not know whether to interpret this as

colored_p({ a: 'hash' }, color: 'red')

or as

colored_p(nil, a: 'hash')

It defaults to the later, and then throws an error.

Worse, this can also happens for any arguments that define to_hash, for example

class User
  attr_accessor :first_name, :last_name

  def to_hash
    { first_name: first_name, last_name: last_name }
  end
end

colored_p(User.new)  # ArgumentError: unknown keywords: first_name, last_name

This behavior is not very smart.

The easy fix is just to never mix optional and keyword arguments in the first place, so there can never be any ambiguity.

Posted by Tobias Kraze to makandra dev (2015-09-30 10:26)