I’d have to find and/or recreate my test cases for this, but `&foo/1` is
functionally equivalent to `fn x -> foo(x) end` and to `apply(__MODULE__,
:foo, [x])` and it seemed to me that any such capture is treated as a
dynamic (runtime resolution) function, acting as a bit of an optimization
barrier (the internal function could be optimally performed, but there's no
way to inline the behaviour of the internal function).

This could change in the future, but I *think* would require cooperation
from the BEAM as well as improvements to the Elixir compiler (that I am in
no way qualified to discuss).

Understand that when I say that there was a performance hit, we're still
talking about a *massive* IPS value in either case, but it’s worth noting.

I probably wouldn't use either a `then_if/3` as previously proposed or your
`then/3` extension, because I think that there are more expressive ways to
do this, and even avoid the use of `then/2`. A large part of this is
because I used to do things like:

…
|> case do
  …
end
|> case do
  …
end

Which I now consider unreadably complex and would rather see function names
over complex `then/2` or `case/2` pipes.

-a

On Mon, Aug 5, 2024 at 2:10 PM Caio Oliveira <caio...@gmail.com> wrote:

> 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
> <https://groups.google.com/d/msgid/elixir-lang-core/CAJLj4H_Yt6-%2B_TkfeNR-q28COp8b4dicopT88CYujWXX4XRM5Q%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 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/CAJ4ekQuNF-%3Dtsf748N9B81QegR5qMb8p%2BSSHC%3DWtRe0gb5Tthg%40mail.gmail.com.

Reply via email to