Hello, Jose.

Thank you. :)

I was thinking about adding an Access.find!/1, but since there's no 
equivalent Enum.find!/2 I stopped thinking about it. But yes, in deep 
updates it might make more sense than in the Enum.find/2 case.

Best regards,
Oliver

On Wednesday, March 20, 2024 at 12:44:08 PM UTC+1 José Valim wrote:

> Thank you. It seems the major objection was "waiting for a use case".
>
> There is a question about: what happens if you try to update an element 
> that does not exist. But the behaviour in the PR mirrors `at`. We may want 
> to introduce `find!` in the future to mirror `at!` as well.
>
> On Wed, Mar 20, 2024 at 12:00 PM 'oliver....@googlemail.com' via 
> elixir-lang-core <elixir-l...@googlegroups.com> wrote:
>
>> This is what I found:
>>
>> From the original PR: https://github.com/elixir-lang/elixir/pull/6634 
>> (this has a lengthy discussion on the merits).
>>
>> The original discussion about including both: 
>> https://groups.google.com/g/elixir-lang-core/c/LlZCz0iYgfc/m/5XLRvg8XAgAJ 
>> (not very detailed, discussion happened in PR it seems).
>>
>> A discussion from one before that: 
>> https://groups.google.com/g/elixir-lang-core/c/WtKXtP0XFqc/m/73gSelgJBgAJ 
>> (there was disagreement about the best data structure for the actual use 
>> case)
>>
>> That's all I found.
>>
>> Best regards,
>> Oliver
>>
>> On Wednesday, March 20, 2024 at 11:40:15 AM UTC+1 José Valim wrote:
>>
>>> Can you please provide a link to the previous discussions? I recall 
>>> dealing with some complexities around finding and not finding elements as 
>>> well. Thanks!
>>>
>>> On Wed, Mar 20, 2024 at 11:37 AM 'oliver....@googlemail.com' via 
>>> elixir-lang-core <elixir-l...@googlegroups.com> wrote:
>>>
>>>> Hello, okay I checked.
>>>>
>>>> Well, there was a discussion 7 years ago when Access.filter/1 was 
>>>> introduced but Access.find/1 was not.
>>>>
>>>> Maybe opinions might have changed since then?
>>>>
>>>> When going into the PR from back then I find the reasoning not very 
>>>> strong on not merging Access.find/1 because "it could be expressed by a 
>>>> more strictly defined Access.filter/1". 
>>>>
>>>> I don't find that to be true. It has pretty much has the same use cases 
>>>> as Enum.find/2 when used with get_in/2, for example. 
>>>>
>>>> Writing a very convoluted filter predicate to catch only the first 
>>>> occurrence when you really need to do that - we basically found that to be 
>>>> very unelegant. I really tried to cram our use case into the 
>>>> Access.filter/1 approach and it was not good.
>>>>
>>>> An added benefit is that we do not walk the rest of the list - once an 
>>>> element is found, the tail is just appended in updates. It has therefore a 
>>>> slightly better performance for its specific use case over 
>>>> Access.filter/1. 
>>>> You also don't get a list you have to Access.all after. I mean, it's 
>>>> basically like Enum.find/2 instead of Enum.filter/2.
>>>>
>>>> Btw, our use case was as follows:
>>>>
>>>> We have a data structure representing a testcase to be run. Later on we 
>>>> want to verify some counter updates done in that TC. We reuse the data 
>>>> structure describing the TC. For this particular requirement regarding the 
>>>> counter updates only the first occurrence of a particular procedure will 
>>>> behave different. It has no other criteria it is different or can be told 
>>>> apart by, so we just update the first occurrence for this check with a 
>>>> flag 
>>>> for easier post-processing of the counter data. This flag has no relevance 
>>>> to other parts of our testing system, and if TC authors add it manually, 
>>>> they might forget. We simply use internally Access.find/1 to specifically 
>>>> pick that one.
>>>>
>>>> When you have very clear, distinct criteria like in a DB row update 
>>>> (like there's only one "Jane Smith" with ID 42) then there would be no be 
>>>> advantage over Access.filter/1. So it's situational, but in the situations 
>>>> it's useful it's hard to express otherwise. For example once you 
>>>> Access.filter/1 you can no longer do something like Access.at/1 because it 
>>>> directly moves you into the elements.
>>>>
>>>> Sorry for the long post, but I hope it conveys the rationale.
>>>>
>>>> Best regards, 
>>>> Oliver
>>>>
>>>>
>>>>
>>>>
>>>> On Wednesday, March 20, 2024 at 10:07:33 AM UTC+1 an.le...@gmail.com 
>>>> wrote:
>>>>
>>>>> Right now I’m a bit drowning in work but IIRC there already was a 
>>>>> proposal for this, has anyone searched the mailing list?
>>>>>
>>>>> On Wed, Mar 20, 2024, at 12:17 AM, Jean Klingler wrote:
>>>>>
>>>>> I like it. It would be to `Access.filter` what `Enum.find` is to 
>>>>> `Enum.filter`.
>>>>> I think it would be a nice addition as it can express operations that 
>>>>> would be quite verbose otherwise.
>>>>>
>>>>> Le mer. 20 mars 2024 à 02:30, 'oliver....@googlemail.com' via 
>>>>> elixir-lang-core <elixir-l...@googlegroups.com> a écrit :
>>>>>
>>>>> Hi.
>>>>>
>>>>> I already made a PR but was redirected here. ;-)
>>>>>
>>>>> This new function Access.find/1 would basically work like Enum.find/2 
>>>>> but for get_in/2 and similar functions.
>>>>>
>>>>> It can be used for scenarios like:
>>>>> - Popping the first found element.
>>>>> - Updating only the first found match in a list.
>>>>> - To get_in/2 an element directly instead of piping from get_in/2 into 
>>>>> Enum.find/2.
>>>>>
>>>>> The implementation is very similar to Access.filter/1 and Access.at/1.
>>>>>
>>>>> We added this functions as utility function in our own project because 
>>>>> we couldn't really find an elegant way to do such pointed updates with 
>>>>> the 
>>>>> existing functions.
>>>>>
>>>>> These are the examples I would have included in the doc string:
>>>>>
>>>>>       iex> list = [%{name: "john", salary: 10}, %{name: "francine", 
>>>>> salary: 30}]
>>>>>       iex> get_in(list, [Access.find(&(&1.salary > 20)), :name])
>>>>>       "francine"
>>>>>
>>>>>       iex>  get_and_update_in(list, [Access.find(&(&1.salary <= 40)), 
>>>>> :name], fn prev ->
>>>>>       ...> {prev, String.upcase(prev)}
>>>>>       ...>  end)
>>>>>       {"john", [%{name: "JOHN", salary: 10}, %{name: "francine", 
>>>>> salary: 30}]}
>>>>>
>>>>>       iex> list = [%{name: "john", salary: 10}, %{name: "francine", 
>>>>> salary: 30}]
>>>>>       iex> pop_in(list, [Access.find(&(&1.salary <= 40))])
>>>>>       {%{name: "john", salary: 10}, [%{name: "francine", salary: 30}]}
>>>>>
>>>>>       iex> list = [%{name: "john", salary: 10}, %{name: "francine", 
>>>>> salary: 30}]
>>>>>       iex> get_in(list, [Access.find(&(&1.salary >= 50)), :name])
>>>>>       nil
>>>>>
>>>>>       iex> get_and_update_in(list, [Access.find(&(&1.salary >= 50)), 
>>>>> :name], fn prev ->
>>>>>       ...>   {prev, String.upcase(prev)}
>>>>>       ...> end)
>>>>>       {nil, [%{name: "john", salary: 10}, %{name: "francine", salary: 
>>>>> 30}]}
>>>>>
>>>>> Thanks,
>>>>> Oliver
>>>>>
>>>>>
>>>>> -- 
>>>>> 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/44ed5beb-1730-46d7-931a-217825cc4432n%40googlegroups.com
>>>>>  
>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/44ed5beb-1730-46d7-931a-217825cc4432n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>>>
>>>>> -- 
>>>>> 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/CANnyoha%2BwMRpTy_H2%3Dwy8sWjSQgXPpY-cbaL65Tx7D_AK7o1GA%40mail.gmail.com
>>>>>  
>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CANnyoha%2BwMRpTy_H2%3Dwy8sWjSQgXPpY-cbaL65Tx7D_AK7o1GA%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>>>
>>>>> -- 
>>>> 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/61e2ada8-1ba6-4945-9013-2cec1d1cf457n%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/elixir-lang-core/61e2ada8-1ba6-4945-9013-2cec1d1cf457n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> -- 
>> 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/05347e87-a2ff-41b2-81a1-b30fc423adcbn%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/elixir-lang-core/05347e87-a2ff-41b2-81a1-b30fc423adcbn%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
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-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/7513b934-49eb-44fa-99a3-f5d6141393ccn%40googlegroups.com.

Reply via email to