# Fixing the Piping/Chaining Issue

**URL:** <https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654>\
**Category:** Internals & Design\
**Tags:** proposal, piping, chaining, partial-evaluation, threading\
**Created:** [November 2, 2022, 11:04am UTC](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654 "2022-11-02T11:04:36Z")\
**Posts on this page:** 1\
**Showing post:** 211

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [November 11, 2022, 7:02am UTC](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654/211 "2022-11-11T07:02:04Z")

</div>

> **So I'm revisiting this, and I thought the extra time was from compiling but it's not.**
>
> > [@Sukera](#):
> >
> > > [@uniment](#):
> > >
> > > Yes, I believe this is the point. I don’t want any runtime computation whatsoever for something that just calls another function.
> > 
> > Literally the only reason the compiler was able to fold your computation was because the input to your `Fix` thing was part of the benchmarking expression. Here, let me help you out:
> > 
> > ```julia
> > julia> @benchmark Fix{(1,2,-3,-1)}(f, vals, z=5)(args...; kw...) setup=(f=(args...;kwargs...)->(args...,(;kwargs...));vals=(:a,:b,:getting_close,:END); args=(:y, 1, 2); kw=(:k=>2,))
> > BenchmarkTools.Trial: 10000 samples with 1 evaluation.
> > Range (min … max): 52.667 μs … 176.066 μs ┊ GC (min … max): 0.00% … 0.00%
> > Time (median): 53.412 μs ┊ GC (median): 0.00%
> > Time (mean ± σ): 55.087 μs ± 5.945 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
> > 
> > ▆█▅▂▁ ▃ ▁
> > █████▆▅█▆▆▇▆▄▅█▆▅▆▆▄▄██▇▅▅▇▆▆▇▆▅▅▆▅▅▆▅▅▅▄▄▄▄▄▂▄▄▄▄▄▅▂▃▄▄▅▅▅▆ █
> > 52.7 μs Histogram: log(frequency) by time 84.9 μs <
> > 
> > Memory estimate: 2.59 KiB, allocs estimate: 45.
> > 
> > julia> @btime Fix{(1,2,-3,-1)}(f, vals, z=5)(args...; kw...) setup=(f=(args...;kwargs...)->(args...,(;kwargs...));vals=(:a,:b,:getting_close,:END); args=(:y, 1, 2); kw=(:k=>2,))
> > 52.683 μs (45 allocations: 2.59 KiB)
> > (:a, :b, :y, 1, :getting_close, 2, :END, (k = 2, z = 5))
> > 
> > ```
> > 
> > And ok, you might argue “but the function is fixed!”, then here, have this benchmark where only the input is not known and thus can’t be folded:
> > 
> > ```julia
> > julia> @benchmark Fix{(1,2,-3,-1)}((args...;kwargs...)->(args...,(;kwargs...)), (:a,:b,:getting_close,:END), z=5)(args...; kw...) setup=(args=(:y, 1, 2); kw=(:k=>2,))
> > BenchmarkTools.Trial: 10000 samples with 1 evaluation.
> > Range (min … max): 51.705 μs … 203.229 μs ┊ GC (min … max): 0.00% … 0.00%
> > Time (median): 52.434 μs ┊ GC (median): 0.00%
> > Time (mean ± σ): 54.838 μs ± 7.742 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
> > 
> > ██▄▂ ▁ ▁ ▂▂ ▁ ▂
> > ███████▇▇█▁▇█▆▆█▅▅██▇▆█████▇▇██▇▇▇▇▇▆▆▆▇▆▇▆▆▆▆▅▆▆▆▇▇▆▆▅▆▆▆▄▅ █
> > 51.7 μs Histogram: log(frequency) by time 89 μs <
> > 
> > Memory estimate: 2.55 KiB, allocs estimate: 44.
> > 
> > julia> @btime Fix{(1,2,-3,-1)}((args...;kwargs...)->(args...,(;kwargs...)), (:a,:b,:getting_close,:END), z=5)(args...; kw...) setup=(args=(:y, 1, 2); kw=(:k=>2,))
> > 51.934 μs (44 allocations: 2.55 KiB)
> > (:a, :b, :y, 1, :getting_close, 2, :END, (k = 2, z = 5))
> > 
> > ```
> > 
> > It’s not better. The only case where it _could_ be better is if everything is tuple, always, which is just not a realistic use case.
> > 
> > To me your reply just shows that you’re ignorant about what you’re actually defining and how that actually works. This is not convincing.

I’m not sure why, but when I run the exact same benchmark it’s quite a bit faster on my machine:

```julia
julia> @btime Fix{(1,2,-3,-1)}(f, vals, z=5)(args...; kw...) setup=(f=(args...;kwargs...)->(args...,(;kwargs...));vals=(:a,:b,:getting_close,:END); args=(:y, 1, 2); kw=(:k=>2,))
  753.913 ns (18 allocations: 1.06 KiB)
(:a, :b, :y, 1, :getting_close, 2, :END, (k = 2, z = 5))

```

Still, it could be faster. The setup argument `kw=(:k=>2,)` leads to type-instability (making namedtuples out of pairs, dicts, etc. is type-unstable). So let’s change that to `kw=(k=2,)`:

```julia
julia> @btime Fix{(1,2,-3,-1)}(f, vals, z=5)(args...; kw...) setup=(f=(args...;kwargs...)->(args...,(;kwargs...));vals=(:a,:b,:getting_close,:END); args=(:y, 1, 2); kw=(k=2,))
  1.500 ns (0 allocations: 0 bytes)
(:a, :b, :y, 1, :getting_close, 2, :END, (k = 2, z = 5))

```

Ah, that’s better.

---

_[View the full topic](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654)._
