[Proposal] Map.take!/2

116 views
Skip to first unread message

Aaron Tinio

unread,
Nov 30, 2016, 6:25:18 PM11/30/16
to elixir-lang-core
Map.take!(map, keys)

Same as Map.take/2 but raises a KeyError when one of the keys doesn't exist.

Tallys Martins

unread,
May 24, 2018, 4:11:25 PM5/24/18
to elixir-lang-core
Hi!

I could not find a final reply for this thread, here nor at Github, so I am here to ask and argue why this would be a useful function.

I am writing some tests where I pattern match just a few keys of my map objects using Map.take. Developers could type invalid keys and the tests would still pass.
If you are open to receive an implementation for this I can work on it and give my first piece of contribution.

Sorry for reviving something deep in the past if its already solved.

Warm Regards,
Tallys Martins

Peter Hamilton

unread,
May 24, 2018, 4:46:49 PM5/24/18
to elixir-l...@googlegroups.com
Thanks for searching for an old thread rather than making a new one!

I pattern match just a few keys of my map objects

Would just doing a direct pattern match work here?

%{foo: foo, bar: bar} = my_map

That would fail if foo or bar was missing in my_map.

--
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/6c898b72-6626-4738-8331-cdee13cff251%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tallys Martins

unread,
May 24, 2018, 5:57:29 PM5/24/18
to elixir-l...@googlegroups.com
Well, this does not suites for my cases because I actually have object maps like %Measurement{}. The problem comes when I need to pattern match its attributes like id and others. Let me give you some context, but maybe I am going through the wrong solution, though.

This code:

assert expected_measurement = measurement 

would fail because association attributes in measurement are not loaded Ecto.Association.NotLoaded (and they are supposed to)

So I selected the ones that I care, not simple the id, but to resume:

assert %Measurement{id: ^expected_measurement.id} = measurement

And this raise an error: cannot invoke remote function expected_measurement.id/0 inside match 

So I decided to use Map.take/2 on both maps checking a list of attributes that I think that matters the most. The problem is that if one comes with an attribute that does not exists, the tests will equally pass, so I thought it would be good to have a Map.take!/2 function to help on that.

Martin Svalin

unread,
May 25, 2018, 5:00:03 AM5/25/18
to elixir-l...@googlegroups.com
So essentially you are concerned with this scenario?

```elixir
actual = Map.take(DateTime.utc_now, [:yaer, :month]) # note misspelling
expected = Map.take(%{year: 2017, month: 6, day: 1}, [:yaer, :month]) # same misspelling
assert actual == expected  # passes even though we're in 2018
```

I would write that as 

```elixir
assert %{yaer: 2018, month: 6} = DateTime.utc_now
```

Which would fail for the correct reason: the misspelling. Fixing this would reveal the test failure that 5 != 6.
You'd have similar failures if your tests were correctly spelled, but your data was misspelled or missing keys.

I'm not opposed to the idea of a `Map.take!` that raises KeyError. I don't have a use case handy, though.

- Martin

Martin Svalin

unread,
May 25, 2018, 5:01:33 AM5/25/18
to elixir-l...@googlegroups.com
(edited to have the year fail instead of the month, but didn't edit enough… month: 5, 2017 != 2018… you get the gist. Sorry)

Tallys Martins

unread,
May 26, 2018, 1:25:58 PM5/26/18
to elixir-l...@googlegroups.com
Thanks for the replies!

Em sex, 25 de mai de 2018 às 06:00, Martin Svalin <martin...@gmail.com> escreveu:
So essentially you are concerned with this scenario?

```elixir
actual = Map.take(DateTime.utc_now, [:yaer, :month]) # note misspelling
expected = Map.take(%{year: 2017, month: 6, day: 1}, [:yaer, :month]) # same misspelling
assert actual == expected  # passes even though we're in 2018
```
Yes, something like this!

I would write that as 

```elixir
assert %{yaer: 2018, month: 6} = DateTime.utc_now
```
You are right, this is a better approach. No more need for Map.Take/2. I realized that my scenario was similar to testing Repo.one, I took a look at ecto's codebase and this is exactly what they did in their tests. Thanks!

Which would fail for the correct reason: the misspelling. Fixing this would reveal the test failure that 5 != 6.
You'd have similar failures if your tests were correctly spelled, but your data was misspelled or missing keys.

I'm not opposed to the idea of a `Map.take!` that raises KeyError. I don't have a use case handy, though.
We can wait someone bring real a use case. Thanks for your reply.

Tallys
Reply all
Reply to author
Forward
0 new messages