Proposal: Add List.keyfetch!/2

84 views
Skip to first unread message

Wojtek Mach

unread,
Jul 6, 2021, 7:38:42 AM7/6/21
to elixir-lang-core
When working with lists of two element tuples like:

    headers = [{"content-type", "html"}]
    attributes = [{"href", "https://elixir-lang.org"}]

I'd usually access the value like this:

    {_, content_type} = List.keyfind(headers, "content-type", 0)
    IO.puts content_type

And when the value is not there, I'd get:

    ** (MatchError) no match of right hand side value: nil

I'd like to propose adding a new function so instead we could do:

    IO.puts List.keyfetch!(headers, "content-type")

This function can give a better error message and is pipe friendly. It only works on lists with k/v, hence using the word fetch which reminds us of `Map.fetch`, `Keyword.fetch`, etc.

## Example implementation

    def keyfetch!(list, key) do
      case List.keyfind(list, key, 0) do
        {_, value} ->
          value

        nil ->
          raise "key not found: #{inspect(key)}"

        tuple ->
          raise "expected list to contain two-element tuples, got: #{inspect(tuple)}"
      end
    end

## Q & A

Q: Why not `List.keyfind!(list, key, position)` that returns the value?

A: The crux of the proposal is to be able to do this:

    List.keyfind!([{"a", 1}], "a", 0)
    #=> 1

But given it is called `keyfind` we should also handle this and it is unclear what
it should return:

    List.keyfind!([{"a", 1, 2}], "a", 0)
    #=> ???

Q: Why not `List.keyfind!(list, key, position)` that returns the tuple?

A: I think that'd be an improvement although we'd still have to manually unpack the value which is a bit annoying.

Q: Why not `List.keyfetch!(list, key, position \\ 0)`?

A: I'd be ok with that.

Q: Should there also be a non-raising variant, `List.keyfetch(list, key)`?

A: In that case I think it's fine to pattern match on `List.keyfind/3` but yeah, I could see it added for consistency.

José Valim

unread,
Jul 6, 2021, 8:20:20 AM7/6/21
to elixir-l...@googlegroups.com
I think having a function in the shape of List.key* but one that assumes a certain shape (i.e. a two-element tuple) is counter-intuitive. We could have List.keyfind!(...) but it should still return a tuple in case of success. :)

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/f82edae0-c129-4d39-946e-7f15576f271an%40googlegroups.com.

Wiebe-Marten Wijnja

unread,
Jul 6, 2021, 8:54:48 AM7/6/21
to elixir-l...@googlegroups.com

The disadvantage of introducing functions like this,
is that we inevitably end up with duplication between functions which work in general in `List`,
as well as functions which work the same way, but only if the key(s) in the list happen to all be atoms, in the `Keyword` module.

Maybe we can reconsider the restriction that `Keyword` requires all keys to always be atoms? Could we loosen this restriction?

~Wiebe-Marten / Qqwy

OpenPGP_signature
Reply all
Reply to author
Forward
0 new messages