spacebat

spacebat

A recent Reddit post Keyword.get Considered Harmful nudged me to tidy up and publish a small utility library that I’ve been using to deal with keyword lists in an ergonomic way.

Elixir keyword lists as a common representation of optional arguments to functions feels a bit clunky. You may find yourself writing something like:

  def update_user_details(opts \\ []) do
    opts = Keyword.validate!(opts, [:name, :email, role: :guest, gender: :unspecified])
    name = Keyword.fetch!(opts, :name)
    email = Keyword.fetch!(opts, :email)
    ...
  end

The intent of Kword is to enable list matching (there’s an order of parameters in the second argument) and to write instead:

  def update_user_details(opts \\ []) do
    [name, email | _rest] = Kword.extract!(opts, [:name, :email, role: :guest, gender: :unspecified])
    ...
  end

If you want to ensure required parameters are in fact supplied, use extract or extract!.

If you don’t want to allow parameters that aren’t specified, use extract_exhaustive or extract_exhaustive!.

And if you just want to pluck values out of a keyword list in the order specified, use extract_permissive which will default parameters to nil that have no default specified.

Perhaps I’ve missed something and this library isn’t actually useful, or there may be some improvement that would make it more worthwhile.

Showing Posts 1 to 10

katafrakt

katafrakt

I also read that post and liked it very much, however I think it missed one opportunity to make the code better with Keyword.validate!:

def update_user_details(opts \\ []) do
  opts = Keyword.validate!(opts, [:name, :email, role: :guest, gender: :unspecified]) |> Map.new()
  %{name: name, email: email} = opts
  # ...
end

By simply converting validated keyword list to a map you can use established Elixir idioms to check for required things, either by using opts.email notation, or by pattern matching. But maybe I’m missing something too :wink:

D4no0

D4no0

It highly depends on what kind of options you accept and how you treat them. The key concept when using keyword list vs map is that you can have duplicated keys in case of the list, then decide whether the new option overrides/appends to the old one.

sodapopcan

sodapopcan

“Considered Harmful” titles always make me think of “Considered Harmful” Essays Considered Harmful :grin:

I’m in favour of validating keyword args and do it myself (personally I use NimbleOptions) but that article hardcore handwaves through the entire premise of how they got there: how on earth did their tests not catch a mis-spelled option?? It sounds like they were passing the option but not actually asserting on its effects. Am I wrong or is there an obvious valid hiccup you can have here?

sodapopcan

sodapopcan

While it’s getting outside the realm of options, keywords also allow us to have order matter in the rarer situations where that’s useful:

from q in query,
  join: u in User,
  on: u.id == q.user_id,
  join: o in Org,
  on: o.id == u.org_id
katafrakt

katafrakt

Fair point, but with using Keyword.get or Keyword.pop you don’t really decide, just take the first value. Most of the usage of keyword lists outside of Ecto I see is a workaround for Elixir not having named arguments, so converting to map makes sense. However you’re right that to keep Keyword.gets behaviour in place you actually need Enum.reverse() |> Map.new().

Well, but we are in the realm of options.

dimitarvp

dimitarvp

I support everything that helps people make less mistakes and dynamic languages like Elixir don’t provide as much protection there.

So firstly, good job. :+1:

Secondly, the linked article does not sell the resulting library to me. Keyword.get and Map.get are something that many Elixir devs, myself included, consider an anti-pattern simply because they don’t discern between “I don’t have the key” and “I have the key but the value is nil” – in some situations this difference is meaningless but I’d bravely claim that in at least 80%, if not 90%, of the Elixir code I had to author or maintain that difference was in fact important but people ignored it and introduced bugs. So just by using functions like take and fetch you can replace most of the conveniences of this library – though granted, it would take more boilerplate so the library still looks compelling.

Thirdly, not comparing the new library with NimbleOptions is giving homework to the reader so I am going to skip it and just use the former instead.

sodapopcan

sodapopcan

The discussion is turning into a more general “why keyword lists over maps or bringing in keyword args,” so not quite, no.

spacebat

spacebat OP

Converting to Map was my first impulse, and I guess I should benchmark it but seems a bit heavyweight compared to constructing a list. Also there is the gotcha of Map.new taking the last one if a key occurs more than once.

spacebat

spacebat OP

I have seen NimbleOptions but bounced off when I saw how verbose it was, defining a schema with types. Looking closer now I do think there would be times I’d want exactly that.

The aim of Kword is to provide a few relatively fast functions that I found myself wishing were in the Keyword module.

sodapopcan

sodapopcan

Oh ya, I got that! I wasn’t speaking against the utility of your library, just criticizing the article you linked.

Where Next? Top

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
387 15136 120
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
New
kip
Please say hi to a new lib, Astro that aims to deliver easy-to-consume astronomy calculations of practical use. For now it only calculat...
New

Other Trending Topics Top

akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews