Thank you @sgaure for the explanation and helpful hints. Iβd like to add a few more points here.
In fact, when I tried benchmarking using @btime
, which was recommended over @time
, the gap was even wider than in my original post.
julia> VERSION
v"1.8.5"
julia> @btime [fact1(n) for n = 1:20] ;
3.999 ΞΌs (1 allocation: 224 bytes)
julia> @btime [fact2(n) for n = 1:20] ;
240.244 ns (1 allocation: 224 bytes)
Next, I tried to address the Any
return type issue mentioned in your response by explicitly providing a return type:
fact3(n) = fact3(Val(n))
(fact3(::Val{n})::Integer) where {n} = n*fact3(Val(n-1))
fact3(::Val{1}) = 1
Which results in the forced return type being used:
julia> @code_warntype fact3(4)
MethodInstance for fact3(::Int64)
from fact3(n) in Main at REPL[10]:1
Arguments
#self#::Core.Const(fact3)
n::Int64
Body::Integer
1 β %1 = Main.Val(n)::Val
β %2 = Main.fact3(%1)::Integer
βββ return %2
But the benchmark was similar to fact1
or slower! Perhaps you meant Val
to be the problem instead of the Any
return type?
julia> @btime [fact3(n) for n = 1:20] ;
4.851 ΞΌs (9 allocations: 544 bytes)
Nevertheless, for constants, as earlier, we have full folding:
julia> @code_warntype fact3(Val(4))
MethodInstance for fact3(::Val{4})
from fact3(::Val{n}) where n in Main at REPL[11]:1
Static Parameters
n = 4
Arguments
#self#::Core.Const(fact3)
_::Core.Const(Val{4}())
Body::Int64
1 β %1 = Main.Integer::Core.Const(Integer)
β %2 = $(Expr(:static_parameter, 1))::Core.Const(4)
β %3 = ($(Expr(:static_parameter, 1)) - 1)::Core.Const(3)
β %4 = Main.Val(%3)::Core.Const(Val{3}())
β %5 = Main.fact3(%4)::Core.Const(6)
β %6 = (%2 * %5)::Core.Const(24)
β %7 = Base.convert(%1, %6)::Core.Const(24)
β %8 = Core.typeassert(%7, %1)::Core.Const(24)
βββ return %8
julia> @code_native fact3(Val(4))
[...]
movl $24, %eax
retq
[...]
In conclusion, this style of programming not suitable for Julia? Or is there any way we can make Styles 1 and 2 have similar performance for small functions? Or should we use Style1, which uses inbuilt multiple-dispatch, only for heavy-weight functions?
Edit 1: Added the doubt about Val
or Any
.
Edit 2: Added missing word.