3 ms·
You know that maps as envisioned in the EEP (http://www.erlang.org/eeps/eep-0043.html http://www.erlang.org/eeps/eep-0043.html) should let you do pattern matchi
by mononcqc 13y ago
You know that maps as envisioned in the EEP (http://www.erlang.org/eeps/eep-0043.html http://www.erlang.org/eeps/eep-0043.html) should let you do pattern matching using variables, right? It's not there now because it's a provisional implementation, but it will be there.
We will be able to do X = 3, #{X := Val} = Map, ... to extract the value of 'Val' under the unknown key 'X'. This just hasn't been implemented yet, but is part of the total specification.
What you see is the incomplete implementation of maps, not up to the total spec, because this is a RC1 implementation. They will support part of the record use case, but the entirety of the dict use case with more flexibility there (including comprehensions, from_list, etc.)
They are, by specification and once complete, going to be far more feature-equivalent with dicts than records.
- colanderman 13y agoWe will be able to do X = 3, #{X := Val} = Map, ... to extract the value of 'Val' under the unknown key 'X'. Yes. I don't understand the use case for that.
- lostcolony 13y agoI think you may be reading too much into it. The goal is to be able to replace dict/orddict it seems like. For that, we need some way to be able to get values out for keys that are unknown at compile time (and pattern matching is a lovely way of doing that). That is, let's say I have an in memory map of IDs to counters (for whatever reason). I can write an implementation to increment and get the counter value for a given ID (assuming this is a gen_server and this is the call implementation) like so (well, possibly like so. I haven't used maps yet; haven't looked at the early r17 builds yet) - handle_call{{incrementAndGet, Id}, _, State) -> #{Id := Val} = State, NewVal = Val + 1, {reply, NewVal, State#{Id := NewVal}}. The comparable implementation right now, using a dict/orddict, might look like - handle_call{{incrementAndGet, Id}, _, State) -> Val = orddict:fetch(Id, State), NewVal = Val + 1, {reply, NewVal, orddict:store(Id, NewVal, State)}. TL;DR - Do you need to be able to get out a value, given a key? Yes. How do you read out values given a key? Pattern match, as described. PS - Because it pattern matches, if I decided I didn't want to throw if the thing doesn't exist, I can do cool stuff like - handle_call{{incrementAndGet, Id}, _, State) -> NewVal = case State of #{Id := Val} -> Val + 1; _ -> 1 end, {reply, NewVal, State#{Id => NewVal}.
- colanderman 13y ago#{Id := Val} = State Val = orddict:fetch(Id, State) Sorry, I don't see the benefit of one over the other. I do know that one ties me to a specific implementation of a map that may or may not work well for my data if I use it, and that merely by existing, prevents O'Keefe's frames from being implemented in an optimized fashion.
- lostcolony 13y agoOkay, so what you meant was not that you don't see a use case, but rather, you don't see why they implemented maps as a replacement to dict/orddict, and in lieu of frames. Those are different questions, the latter of which not one I feel capable of answering, given that I wasn't involved with the discussions. I assume the reason for wanting to replace dict/orddict is because they feel very much a second class citizen in the language (see at bottom for a comparison of why pattern matching trumps separate modules), dicts are inefficient for small collections, and orddicts are inefficient for anything but small collections. As to why they went this route instead of frames, I recall seeing it in the discussions (I believe the Erlang mailing list but I can't recall), but I never paid that much attention to it. But then, to the first, why not just keep the dict/orddict syntax, a completely frivolous example, solely created to demonstrate why pattern matching is cleaner then dict/orddict - %This just increments a map if the password passed in matches, sets the counter to one and the password to the passed in password if the map does not contain a password, and throws if the password does not match, but does exist. incrementAndGetIfAllowed(Map, Password) -> case Map of #{password := Password, count := Count} -> {Count + 1, Map#{count := Count +1}; #{password = _} -> throw(bad_password_can_not_increment); _ -> {1, Map#{count => 1, password => Password} end. %We have to extract first, then do our logic separately. Behaves the same as the prior function. incrementAndGetIfAllowed(OrdDict, Password) -> CachedPassword = orddict:find(password, OrdDict), CachedCount = orddict:find(count, OrdDict), case {CachedCount, CachedPassword} of {{ok, Count}, {ok, Password}} -> {Count + 1, orddict:store(count, Count + 1, OrdDict)}; {_, {ok, _}} -> throw(bad_password_can_not_increment); _ -> orddict:store(password, Password, orddict:store(count, Count + 1, OrdDict)) end. And that's just with a map/dict holding two things. If you have complicated logic based on the internals of the map/dict, it could remain pretty elegantly matched upon with the map, while getting exponentially uglier using a dict/orddict.