Accepting optional options in Elixir

Bruce Pomeroy
2 min readMay 26, 2017

--

It’s a common pattern to write a function where the last parameter is a set of options that are all optional. Typically you also want to have default values. It’s conventional in Elixir to use a keyword list as this last parameter. I’m not going to discuss the merit of this, in some cases a map might make more sense but I think keyword lists are so conventional for this that I’d be hesitant to stray from them for fear of causing confusion. There‘s an interesting issues here: you can of course pattern-match on keyword lists to extract parameters but the order of the list matters. If someone calls the function with [color: "red", shape: "square"] instead of [shape: "square", color: "red"] you won’t get a match.

Below we accept an options argument and set options to an empty list if it’s not provided. Then we use Keyword.get to pull out the keys wwe’re interested in if they exist, the third parameter we pass to Keyword.get/3 is a default value to use if the key’s not found. No pattern matching used here. Nice and explicit but could get tedious if there are lots of options.

@default_color "black
@default_shape "circle"
def draw(options \\ [] ) do
color = Keyword.get(options, :color, @default_color)
shape = Keyword.get(options, :shape, @default_shape)
IO.puts("Draw a #{color} #{shape}")
end

Below is an alternative approach, we take advantage of pattern matching to extract values but we have to convert to a map first. We can create our default as a map then merge values from the keyword list passed in.

@defaults %{color: "black", shape: "circle"}def draw(options \\ [] ) do
%{color: color, shape: shape} = Enum.into(options, @defaults)
IO.puts("Draw a #{color} #{shape}")
end

--

--

Bruce Pomeroy

Full-stack developer, specializing in Elixir and React