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.