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.