KWargs vs Explicit Maps: A Fight to the Death?

This is a blog about the development of Yeller, The Exception Tracker with Answers

Read more about Yeller here

A recent discussion on the clojure mailing list bought to mind an interesting code style question:

Should apis use keyword arguments, or take a map of options?

That is, should I be calling your api with

(some-api :some-arg 1 :some-other-arg 2)

or

(some-api {:some-arg 1 :some-other-arg 2})

I’ll call the first of those “kwargs”, and the second “an options map” for convenience in the rest of this article.

Looking across the open source libraries Yeller relies on (which is quite a lot - 67 entries in :dependencies in the project.clj right now), both styles are relatively common. But there are some big differences between them.

So which style should you use if you’re writing new code?

I much prefer the second style, passing explicit maps rather than implicit ones. The biggest reason is that it’s much easier to work with functions that take options maps. You can pass the option map around as a value in your program easily, it’s noticeably faster if you ever write wrappers of these functions (otherwise every wrapper is calling apply and unrolling/rolling up options maps).

Here’s what happens when you use the kwargs style and I want to wrap it (say, I want to have my own function that adds a default option, which is very common):

(defn my-wrapper [& kwargs]
  (let [options (assoc (apply hash-map kwargs) :my-default-arg 1)]
    (apply (your-api-fn (flatten (into '() options))))))

That’s a bunch of work! It’s much slower too - you have to create and then eliminate a map on each call.

Here’s what it looks like in the case when you use a map:

(defn my-wrapper [options]
  (your-api-fn (assoc options :my-default-arg 1)))

Easier, faster, and much more obvious what’s going on.

However, like many software decisions, it’s a tradeoff. Each point has pros and cons. Here’s the rough list of tradeoffs of each style:

Options Maps:

  • much easier to compose without perf hits
  • easy to add options or build them up programatically
  • no need to call apply
  • two extra characters
  • the official clojure coding standards say to prefer this style (http://dev.clojure.org/display/community/Library+Coding+Standards)

Kwargs:

  • slightly less typing at each call site (two characters)
  • slightly less “noise” when calling (two characters)
  • harder to wrap without perf problems
  • can’t pass options around as a value without calling apply to unwrap them

But opinion is still relatively divided in the Clojure community. There was a good twitter discussion on the matter a while back.

Folk are pretty divided though. Here’s a list of popular/common libraries and their approach to kwargs vs explicit options maps:

explicit maps

kwargs

That’s an incomplete list, partly taken from Yeller’s dependencies, partly from the clojure toolbox, but you can see there are lots of libraries on both sides.

Overall though, I tend to pick libaries that use maps when possible. They end up being far easier to work with in the long term, easier (and faster) to wrap and so on. I think most new programs should be written with explicit maps now. It’s really not worth all the pain and performance hits just to save users from typing two extra characters.

What do you think? Let me know via twitter, I’m @t_crayford on there, or you can always email me: .

This is a blog about the development of Yeller, the Exception Tracker with Answers.

Read more about Yeller here

Looking for more about running production applications, debugging, Clojure development and distributed systems? Subscribe to our newsletter: