Oh, interesting! But I'd imagine in `apply`s case this happens because it needs to figure stuff out at runtime, which shouldn't be the case here, right?
Either way, after thinking about it and looking at `then` usage in the wild I feel like a simpler `condition` term instead of a predicate might be the way to go, so no extra function calls. Em seg., 5 de ago. de 2024 às 14:04, Austin Ziegler <halosta...@gmail.com> escreveu: > Related to something else that I was working on, I ran some benchmarks on > the performance difference between `apply/3`, calling a captured function, > and calling a function directly and the latter was much faster (I want to > say it was 10–15% faster, but this was months ago) whereas `apply/3` and > captured functions were negligibly different between each other. The > proposed `then_if/3` would have one or two captured functions running in > the pipeline; if it is something that runs frequently, those would add up. > > When I'm building the sort of pipeline described, I don't typically have a > `maybe_add_header` *as part of the pipeline*, but instead have something > like > > … > |> add_modified_since(modified_since) > |> add_entity_id(entity_id) > > Those might call `maybe_add_header` inside, or they might just have two > (or more) heads that only add the header if `modified_since` and > `entity_id` are non-`nil` and non-blank. > > I have wanted `{Map,Keyword}.put_if(container, value)` more often, > personally (but not frequently enough to want to propose them). > > -a > > On Mon, Aug 5, 2024 at 10:04 AM Caio Oliveira <caio...@gmail.com> wrote: > >> Hi Amos! Yeah, creating functions with the clear intent is good and >> preferable. What I don't like is having to create these `maybe_` variants >> that don't really add any clarity to the code and just serve to wrap a >> conditional statement and make it "pipeable". Because of that it doesn't >> feel like the current API is serving to guide devs to writing better code, >> but just being more verbose. >> >> Also I second your point of rarely using `then`, but as I said before, in >> that 1% case I need it I think it could be a tad more convenient. >> >> Em seg., 5 de ago. de 2024 às 10:11, Amos King <a...@binarynoggin.com> >> escreveu: >> >>> I rarely use ‘then’ for anything other than reordering arguments for a >>> pipeline. I find that I end up having the same code that is in the ‘then’ >>> in multiple place and leads me to create a function, with an intention >>> revealing name, instead of using ‘then.’ >>> >>> The new functions lead to more readable and quicker grokking of the code >>> on future passes. I’m always trying to code for future me and future others >>> to speed up understanding of the code. I don’t find that this increases >>> understanding. I think it would lead to more use of it and decrease the >>> amount of time it takes future developers to grok the code. >>> >>> Amos King >>> Binary Noggin >>> >>> On Aug 5, 2024, at 07:48, Caio Oliveira <caio...@gmail.com> wrote: >>> >>> >>> Good idea! I searched through github to find more usecases like that to >>> corroborate this change, and here's what I found: >>> >>> - 972 results for just `|> maybe_put`: >>> https://github.com/search?q=language%3AElixir+%22%7C%3E+maybe_put%22&type=code >>> - 214 results for `then(&if...`, where the majority's `else` clause was >>> just `&1`: >>> https://github.com/search?q=language%3AElixir+%22%7C%3E+then%28%22+%26if&type=code >>> >>> This *feels* statistically relevant, considering the occurrence of `|> >>> then` >>> <https://github.com/search?q=language%3AElixir+%22%7C%3E+then%22&type=code> >>> is ~6.2k. >>> >>> I also noticed that most of the uses didn't need the predicate to be a >>> function (and I think in this cases maybe using `|> case do` is even >>> better, and the missing `else` clause won't be a problem here), so maybe >>> this could be even simpler by just taking a value as the condition instead. >>> >>> Also I'm ok with the `then_if` implementation, but I personally still >>> prefer the `then(..., if: pred)` as it reads better to me, but I understand >>> it might be too different from the rest of the kernel code. >>> >>> Em dom., 4 de ago. de 2024 às 00:15, Jean Klingler <sabiw...@gmail.com> >>> escreveu: >>> >>>> Coming back to some of my projects, I indeed found a bunch of similar >>>> cases, e.g. maybe_put_assoc, so even if I'm still on the fence I do see >>>> your point. >>>> >>>> Assuming we introduce it, I'd find it more natural API-wise to have the >>>> condition first and then the action, which might be why the nested `if` >>>> felt more natural to me (consistent with `if`, other conditionals, and also >>>> Clojure's cond). >>>> >>>> |> then_if(fn_ -> modified_since end, &Req.put_header(&1, >>>> "If-Modified-Since", modified_since)) >>>> >>>> >>>> Le dim. 4 août 2024 à 11:22, Caio Oliveira <caio...@gmail.com> a >>>> écrit : >>>> >>>>> Yup, that’s what I usually do, but I see this in many places. >>>>> `maybe_put_header`, `maybe_prepend`, etc., which makes me think that an >>>>> abstraction would be convenient. And yeah, I wrote a `maybe_then` >>>>> initially, but thought it was simple and convenient enough to be in the >>>>> kernel. >>>>> >>>>> On Sat, 3 Aug 2024 at 22:42 Jean Klingler <sabiw...@gmail.com> wrote: >>>>> >>>>>> Thank you for providing a concrete example. >>>>>> >>>>>> Also subjective but I find the following more readable >>>>>> >>>>>> |> then(&if(modified_since, do: Req.put_header(&1, >>>>>> "If-Modified-Since", modified_since), else: &1)) >>>>>> >>>>>> than >>>>>> >>>>>> |> then(&Req.put_header(&1, "If-Modified-Since", modified_since), >>>>>> if: fn_ -> modified_since end) >>>>>> >>>>>> But perhaps this case might benefit from introducing a private >>>>>> function rather than relying on `then`, especially if this is a recurrent >>>>>> use-case in your module/project: >>>>>> >>>>>> defp maybe_add_header(req, _key, nil), do: req >>>>>> defp maybe_add_header(req, key, value), do: Req.put_header(req, key, >>>>>> value) >>>>>> >>>>>> ... >>>>>> |> maybe_add_header("If-Modified-Since", modified_since) >>>>>> |> maybe_add_header("X-Entity-Id", entity_id) >>>>>> >>>>>> It should also be easy define your own then_if/3 macro if you really >>>>>> prefer the clojure style. >>>>>> >>>>>> >>>>>> Le dim. 4 août 2024 à 09:59, Caio Oliveira <caio...@gmail.com> a >>>>>> écrit : >>>>>> >>>>>>> True, although personally I find the one-line `if` kind of >>>>>>> confusing, especially when I was newer to the language. >>>>>>> >>>>>>> > Additionally, your suggestion only implies what happens if `pred` >>>>>>> is falsy while mine is clear. >>>>>>> >>>>>>> This almost convinced me, to be honest! But on the flip side this >>>>>>> makes it possible for you to forget to add a `else` clause, and just >>>>>>> end up >>>>>>> with a `nil` that is potentially hard to find where it came from. >>>>>>> >>>>>>> Jose replied this in the PR (including here to centralize the >>>>>>> discussion and not spam the PR and his email there): >>>>>>> >>>>>>> > I personally would prefer to write the original code or use no >>>>>>> pipeline at all. I don’t think the gain in conciseness justifies the >>>>>>> loss >>>>>>> in readability. >>>>>>> >>>>>>> I'd say I agree with it 99% of the time, but there's this 1% that >>>>>>> makes me miss Clojure's `cond->` >>>>>>> <https://clojuredocs.org/clojure.core/cond-%3E>. The concrete >>>>>>> example that made me write this PR was this: I'm writing a small >>>>>>> internal >>>>>>> library to build requests for a third party service. There are some >>>>>>> options >>>>>>> that, if included, requires me to add headers to a request. The code >>>>>>> looks >>>>>>> something like this: >>>>>>> >>>>>>> ```elixir >>>>>>> def request_entity(opts) do >>>>>>> modified_since = Keyword.get(opts, :modified_since) >>>>>>> entity_id = Keyword.get(opts, :entity_id) >>>>>>> >>>>>>> Req.new(url: "example.com") >>>>>>> |> add_x() >>>>>>> |> authorize() >>>>>>> |> add_body() >>>>>>> |> then(&if(modified_since, do: Req.put_header(&1, >>>>>>> "If-Modified-Since", modified_since), else: &1)) >>>>>>> |> then(&if(entity_id, do: Req.put_header(&1, "X-Entity-Id", >>>>>>> entity_id), else: &1)) >>>>>>> |> Req.request() >>>>>>> end >>>>>>> ``` >>>>>>> >>>>>>> And I'd much rather write something like this instead: >>>>>>> >>>>>>> ```elixir >>>>>>> def request_entity(opts) do >>>>>>> modified_since = Keyword.get(opts, :modified_since) >>>>>>> entity_id = Keyword.get(opts, :entity_id) >>>>>>> >>>>>>> Req.new(url: "example.com") >>>>>>> |> add_x() >>>>>>> |> authorize() >>>>>>> |> add_body() >>>>>>> |> then(&Req.put_header(&1, "If-Modified-Since", modified_since), >>>>>>> if: fn_ -> modified_since end) >>>>>>> |> then(&Req.put_header(&1, "X-Entity-Id", entity_id), if: fn _ -> >>>>>>> entity_id end) >>>>>>> |> Req.request() >>>>>>> end >>>>>>> ``` >>>>>>> >>>>>>> You can see conciseness is not the point*, but readability, >>>>>>> robustness and convenience (a very subjective feeling, so feel free to >>>>>>> ignore the last one). >>>>>>> >>>>>>> Lastly, I know I could change the code in a million ways to avoid >>>>>>> the pattern altogether, maybe even resulting in a cleaner result, but I >>>>>>> feel this small addition would be a nice to have, and is something I >>>>>>> miss, >>>>>>> even if rarely. >>>>>>> >>>>>>> * I left the conciseness out of the picture because I think it's way >>>>>>> less important, but it does play a bit of a part. The actual example >>>>>>> ends >>>>>>> up needing to break the `if` into more lines, which doesn't read as >>>>>>> good in >>>>>>> the middle of the piping. >>>>>>> Em sábado, 3 de agosto de 2024 às 19:09:10 UTC-3, gva...@gmail.com >>>>>>> escreveu: >>>>>>> >>>>>>>> You can already capture the `if` and do it as a one-liner >>>>>>>> >>>>>>>> x |> then(&if(pred(&1), do: f(&1), else: &1)) >>>>>>>> >>>>>>>> so you don't gain much yet add more complexity. Additionally, your >>>>>>>> suggestion only implies what happens if `pred` is falsy while mine is >>>>>>>> clear. >>>>>>>> >>>>>>>> -Greg Vaughn >>>>>>>> >>>>>>>> > On Aug 3, 2024, at 4:16 PM, Caio Oliveira <cai...@gmail.com> >>>>>>>> wrote: >>>>>>>> > >>>>>>>> > x >>>>>>>> > |> then(fn val -> >>>>>>>> > if pred(&1) do >>>>>>>> > f(val) >>>>>>>> > else >>>>>>>> > val >>>>>>>> > end) >>>>>>>> > >>>>>>>> > Into this: >>>>>>>> > >>>>>>>> > x |> then(&f/1, if: &pred/1) >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>> >>>>>> 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/3c468ed7-1db6-46e3-bf23-45c21e501b3bn%40googlegroups.com >>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/3c468ed7-1db6-46e3-bf23-45c21e501b3bn%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>> . >>>>>>> >>>>>> -- >>>>>> You received this message because you are subscribed to a topic in >>>>>> the Google Groups "elixir-lang-core" group. >>>>>> To unsubscribe from this topic, visit >>>>>> https://groups.google.com/d/topic/elixir-lang-core/uM_M-DWh42A/unsubscribe >>>>>> . >>>>>> To unsubscribe from this group and all its topics, 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/CANnyohay83mzBJRgz%3Dy8RZ6cp257u4t8zSfyMKMOfqmSTMvY2A%40mail.gmail.com >>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CANnyohay83mzBJRgz%3Dy8RZ6cp257u4t8zSfyMKMOfqmSTMvY2A%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-core+unsubscr...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H9%3DsUxyupijoKeJbY1TVYQbjoGF7ALzG9_UT8LF8d655A%40mail.gmail.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H9%3DsUxyupijoKeJbY1TVYQbjoGF7ALzG9_UT8LF8d655A%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>> -- >>>> You received this message because you are subscribed to a topic in the >>>> Google Groups "elixir-lang-core" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/elixir-lang-core/uM_M-DWh42A/unsubscribe >>>> . >>>> To unsubscribe from this group and all its topics, 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/CANnyohZzP5KK-JoXV4BdSg4oGjzgW4AfxOeDu6V7SDqBopR0Ww%40mail.gmail.com >>>> <https://groups.google.com/d/msgid/elixir-lang-core/CANnyohZzP5KK-JoXV4BdSg4oGjzgW4AfxOeDu6V7SDqBopR0Ww%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-core+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H8tdQsK_bpxJXaYQawdLLOsYFt%2BKLL28yDqqbv1rUNP5A%40mail.gmail.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H8tdQsK_bpxJXaYQawdLLOsYFt%2BKLL28yDqqbv1rUNP5A%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >>> -- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "elixir-lang-core" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/elixir-lang-core/uM_M-DWh42A/unsubscribe >>> . >>> To unsubscribe from this group and all its topics, 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/28FA3E4F-762F-40C9-864B-053CC20F4938%40binarynoggin.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/28FA3E4F-762F-40C9-864B-053CC20F4938%40binarynoggin.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/CAJLj4H9KN3aN__3YnuD21F%2B9wmzXGp0uE4_9CUUw_zvez2poNA%40mail.gmail.com >> <https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H9KN3aN__3YnuD21F%2B9wmzXGp0uE4_9CUUw_zvez2poNA%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> > > > -- > Austin Ziegler • halosta...@gmail.com • aus...@halostatue.ca > http://www.halostatue.ca/ • http://twitter.com/halostatue > > -- > You received this message because you are subscribed to a topic in the > Google Groups "elixir-lang-core" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/elixir-lang-core/uM_M-DWh42A/unsubscribe > . > To unsubscribe from this group and all its topics, 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/CAJ4ekQuEvC%3D0ptqFOk8TDntk0YLK6pT5wn2mo%3DNRoYd50D6aCQ%40mail.gmail.com > <https://groups.google.com/d/msgid/elixir-lang-core/CAJ4ekQuEvC%3D0ptqFOk8TDntk0YLK6pT5wn2mo%3DNRoYd50D6aCQ%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-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H_Yt6-%2B_TkfeNR-q28COp8b4dicopT88CYujWXX4XRM5Q%40mail.gmail.com.