[FEATURE] Flag maps? shorthand notation

Often I find myself doing this.

whitelist = [:ny, :nj, :fl]
state in whitelist

But this is very poor for performance especially once whitelist grows. So its natural to do this

whitelist = %{ny: 1. nj: 1, fl: 1}
!!whitelist[state]

The 1 value is redundant but it has to be truthy. I know there was ShorterMaps before that never got merged, but I feel like I keep circling back to the Map and how it can be improved.

Being able to do something like this

whitelist = %{ny: :ny, nj: :nj, fl: :fl} = %{ny, nj, fl}

would be super useful. I know its been discussed to death years ago, but bringing it up again as I feel it would save a bunch LOC and readability issues, especially once your keys become like :table_animal_fur_color, :table_animal_paw_color, :table_animal_run_speed.

1 Like

It sounds like you want a https://hexdocs.pm/elixir/MapSet.html

2 Likes

Did not realize MapSet has same logarithmic complexity as Map, I will try it. Thought need to see how it would play around with guards / Access module, MapSet.get, etc?

It doesn’t implement access since it isn’t a KV structure, you’d just say state in whitelist or similar. Unfortunately guard support is poor since it isn’t a true native structure. Maybe the latest OTP changes could actually improve that though with is_map_key, you could make some defguards.

Yea so its not quite the same then as doing %{nj: 1}, in terms of slightly more complex matches and maintaining readability. Not a direct replacement IMO.

!!whitelist[state]

seems decidedly less readable than state in whitelist.

2 Likes

The common issue that I have seen when it comes to this syntax is that a map can have multiple kinds of keys. For example, how should the suggested syntax work for the following map

iex(1)> %{"foo" => "foo", foo: :foo}
%{:foo => :foo, "foo" => "foo"}

I realize that something like this would be exceedingly rare in real code, but that fact of the matter is that it is still allowed by the Elixir compiler. If you, or anyone else, has an answer to this question, there may be a way to move forward with a proposal like this.

With that said, if you are trying to whitelist keys in your map, is there a reason you do not use a struct?


For anyone else that has not seen this kind of proposal before, here are a couple example conversations. I am sure there are others as well…

1 Like

Already we assume itl be atom keys, because access.get only works on atoms. So ignore string keys.

Not whitelist keys in a map, but compare if fields are in a whitelist.

Like we gotta start doing more with maps these days, linked-lists (how erlang implements lists) are going the way of the dinosaur. They confuse modern CPU caching (due to pointer chasing) making them much slower in this generation of computing than other data structures. So like a Enum.find vs Map.get is like 10-20 times slower per member of the list, when you consider the pointer chase penalty.

" seems decidedly less readable than state in whitelist ."
Wish that syntax can work with maps as well.

map = %{atom}
true = :atom in map
1 Like