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> @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> @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.
This again requires the autocomplete to know that d
is a Beta
, which is information you don’t have. Constructors are (sadly) not even required to return an object of their type, meaning you have to run type inference, as I’ve repeated multiple times now, to even begin checking which methods can possibly receive d
.
Again, _
has no relation whatsoever to the “no argument” case because you can’t pipe anything into functions that don’t take any arguments. There is no generalization possible here because the 0 argument case is not a generalization of the 1 argument case, and neither of the n-argument case.
This already has syntax in the form of f(d...) = my_func(x, d...)
, which is MUCH clearer about what’s going on than having to read the second part since ...
already has the established meanings.
Because they are in a statically typed language where the type of every single object is determined just by having a method/function in the first place. In a statically typed language, not knowing the type of a variable is a compiler error. It is not in julia.
It cannot, because Beta
at the syntax level is just another function that can return an object of any type. Running at least type inference to know this is required.
Whether or not the function was created with _
or not has no bearing on which methods are selected. To the compiler, these two things are almost exactly the same, save for the name:
julia> f = (a,b) -> a+b
#3 (generic function with 1 method)
julia> g(a,b) = a+b
g (generic function with 1 method)
Whether f
was created like f = _ + _
or with the explicit anonymous function syntax is irrelevant - the compiler never even sees the difference.
This already exists - annotate your types on every variable. Of course, this completely removes the ability of your code to be reused & generic, which is what you typically get in a static language. If you don’t want to do that and run type inference on every step, we AT LEAST require partial type inference to run up until invalid expressions, but again, that has NOTHING to do with whether you have fancy syntax for defining partially applied functions or not.
I will just repeat myself from above: You want a specific syntax and ascribe to that syntax mythical abilities that have nothing to do whatsoever with the actual semantic problems underneath. OOP languages can have their easy autocomplete on their syntax because they are statically typed; not the other way around.