Skip to content

Comment on Keyword Arguments: Ruby, Clojure, Common Lisp

Comments

Ruby has a penchant for giving you more than enough rope to hang yourself on, and "Ruby keyword arguments" are no different. I've seen them used in the wild. It's horrendous.

The code I had to update was poorly written, but the functions with "keyword arguments" were practically incomprehensible _because I didn't even know what their parameters were_. Furthermore, the interactions between these "keyword arguments" wasn't documented anywhere. Sometimes supplying one keyword demanded that another keyword also be supplied, less the function quietly fails.

Finally, there's no way to make a "keyword argument" a required argument. Every function I saw with keyword arguments was littered with "bar = foo.key?(:bar) ? foo[:bar] : default_value" or "throw Exception if not foo.key?(:bar)"

Don't use hashes as a replacement for argument lists in Ruby. Hack the Ruby source and add real keyword arguments.

edit: added another example

Well, keyword arguments can be used well in ruby, though clearly, in the code you've been dealing with they haven't.

Some guidelines. Use .merge for default values, not ternary operators. Keep it minimal. Rails does a good job of using keywords for stuff that's optional, and positional arguments for stuff that isn't. For instance

    link_to 'My Website', 'http://example.net', :class => 'my-css-class'.
Here, the arguments you need, the link title and href are non-optional positional args. HTML attributes OTOH are option hash args..

It sounds like in the code you've inherited, though I can't be sure, there are fairly complicated hashes being passed around all kinds of places. These should probably be objects, not hashes, in the first place. I'll admit though, I can't be certain from my limited vantage point.

I think the hashes instead of objects paradigm contributed to my frustration.

I ended up turning parts of the hashes into objects and parts into parameters.

You and your sibling post provide some decent guidelines and approaches to default arguments. My experience with Ruby has lead me to believe that it's an awesome language, but a language which I'd be very careful about with whom I collaborated.

Here's an example of how I use the hash as keyword arguments. (Minus the documentation

    def save_record(record, options={}, &block)
      return nil if record.nil?
      options = {
        :add_params => {},
        :as => nil,
        :without_protection => false,
        :params => params[record.class.name.underscore.to_sym],
        :user => current_user,
      }.update options
The important part is: options = {}.update(options)

This pattern works very well for providing defaults and some documentation on what options are available. I still document the options before the function.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.