wmnnd

wmnnd

Function parameters vs Keyword lists

A little while ago, I suggested to add Ecto.Changeset.optimistic_lock/4 in addition to the already existing Ecto.Changeset.optimistic_lock/3. While José didn’t like the idea, he also pointed out that if he were to consider it, he’d prefer modifying the API so that it would accept an opts Keyword list instead of adding optimistic_lock/4.

Ever since that, I have been wondering: When is it preferable to use an opts Keyword list instead of additional function parameters? What criteria do you usually use to decide which one to pick?
In many cases so far, I have found Keyword lists to be less convenient than »regular« parameters since you can’t do pattern matching on them.

My impression is that they might be better for public-facing interfaces in order to have a cleaner API. I’d then extract the values in the public function and work with them in additional private functions where pattern matching can be used again. What are your thoughts on this? Any rules of thumb that you employ when making the decision?

Most Liked

michalmuskala

michalmuskala

In general I would say that, for public functions, whenever you get more than 3 or 4 arguments you should really look into making them all (or at least some of them) a keyword. As @Qqwy mentioned many positional arguments are error prone.

Another, not mentioned yet, but very important use case are boolean arguments. Positional boolean arguments are a horrible API (most of the time), using keywords makes it slightly better since you’re able to name the thing.

Pattern matching on keywords is indeed problematic, but there are ways they can be used cleanly. A solution that I really like and often see in Erlang code, but rarely in Elixir, is reducing over the keyword to build some sanitised state.

Qqwy

Qqwy

TypeCheck Core Team

Keywords are useful if:

  • A function has many parameters, and remembering the order of these is hard. Using a keyword list is nice in this case, since it shows at a function call location what information is used for which purpose inside the function.
  • A function has many optional parameters.
  • A function takes some arguments from the list of options, and passes the rest on. (Note that while this is nice in some cases, it is often a bad idea as it does not ‘fail fast’; you won’t notice right away if you made a typo in the option name, for instance)

An important drawback of keyword lists is that when you ‘just’ use them, your function might be passed without some argument that it needs, so depending on where your function is used, you might want to add some descriptive error messages if people forget to pass it.

As you indeed already mentioned, not being able to pattern-match on them, as the keywords might be passed in any order is another drawback. Therefore, while they are nice in an outward-facing API, internally you’ll probably end up calling a high-arity function anyway.

So, my rule of thumb: Use them when it makes the public-facing code more clear, and use them when there are many optional arguments.

michalmuskala

michalmuskala

You can see an Erlang example in how poolboy process builds its state:

https://github.com/devinus/poolboy/blob/master/src/poolboy.erl#L125-L146

I can’t think of elixir examples right now.


UPDATE: You can see an elixir example in this refactoring of credo (that didn’t actually make it, but shows the idea quite nicely):
https://github.com/rrrene/credo/pull/107/files#diff-6a5ceb395f2a140c73ab593bf06fcb55

https://github.com/michalmuskala/credo/blob/b0811c97f5a509593755f6c7b7c44d6f8d18b3ff/lib/credo/cli.ex#L122-L143

Where Next?

Popular in Discussions Top

mbenatti
Following https://github.com/tbrand/which_is_the_fastest |> https://raw.githubusercontent.com/tbrand/which_is_the_fastest/master/imgs...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
lorenzo
Hey everone! I created a prototype for my app using Nodejs for the api. But the framework I chose wasnt great (in general theresnt any g...
New
nunobernardes99
Hi there Elixir friends :vulcan_salute: In a recent task I was on, I needed to check in two dates which of them is the maximum and which...
New
crispinb
On reading dhh’s latest The One Person Framework it strikes me that Phoenix with LiveView is already pretty much this. However, never hav...
New
matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New

Other popular topics Top

hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31494 112
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement