add Access.pop/3 to support a specific default value#15468
Conversation
|
@tudborg yes, in this case, the container would have to implement it, so this effectively a change of contract from pop/2 to pop/3. I believe originally we had reasons to not go with pop/3 but I can't recall them at the moment. It may be related to how pop_in works and the fact it can abort early too. |
|
Yea, I was looking at using In my specific case, the performance of the pop doesn't really matter, and I don't need nested access. My data isn't nested, so what I do today to emulate def my_pop(container, key, default \\ nil) do
case Access.fetch(container, key) do
{:ok, value} ->
{_also_value, updated_container} = Access.pop(container, key)
{value, updated_container}
:error ->
default
end
endBut an pop_in(container, [Access.key(key, default)])would work for me, if @josevalim Is there a reason for Would that be a better solution? |
|
I believe I'd indeed prefer to change something like Access.key but I am almost sure the selectors in Access are meant to be type precise instead of polymorphic. One option is to add |
|
That's a possibility. I personally don't think container-type specific accessors are very useful. The better ergonomics of Anyway.
It feels reasonable to me that But I also don't know the reason for adding the accessor functions, so the intended use-case might be lost to me. Originally I did not consider the Kernel functions that use Access. I feel like adding Keyword list support to |
|
We can support keywords in key if you need polymorphism. And perhaps introduce map_key and keyword_key for those who want explicitly non polymorphic versions. A PR is welcome! |
I agree.
Wouldn't this make it harder from the type system to infer the actual accepted type? Another idea could be to add |
|
I don’t think the type system should be a primary concern here. We have many polymorphic interfaces and that’s fine. If they are not, the time to revisit them is yet to come. It is not even clear if the type system can infer nested access in general. That’s a bridge to cross later. :) |
|
@sabiwara That would work as well! I like {value, rest} = pop_in(container, [Access.default(key, default)])For my specific use-case {value, rest} = Access.pop(container, key, default)But I get why that might not be desirable, because it forces the container to implement a I still think WDYT? |
|
I think both work and can be useful - after all we have the possibility to add a default for map keys but not for other containers, feels like a gap/inconsistency 🙂 |
|
I find Access.default kind of inconsistent with the other functions and it doesn't tell anything about the type of argument we are expecting. :( |
|
Alright. 👍 Let me throw together a PR for an |
Adds
Access.pop/3which allows specifying a default value for pop (likeMap.pop/3andKeyword.pop/3)Currently I've implemented it completely separate from
Access.pop/2,to avoid compatibility issues with
pop/2.So the underlying container must also implement
Access.pop/3for this to work.For supporting containers, they'd probably just implement a
which would take care of
pop/2andpop/3.But I'm wondering if there might be a better way to handle this such that
pop/2is just an inlinedpop(container, key, nil).