Should I use Val(N) or Val{N}()?

I wanted to ask whether I can safely use Val(N) instead of Val{N}().

In this example

@code_warntype Val(1)

@code_warntype Val{1}()

in the REPL I get completely different outputs. The result is inferrable in
the second case but not in the first one.

However, in the Julia manual, the use of Val(N) is advocated when N is passed
as a parameter, combined with the function-barrier trick.

On the contrary, when I check the output of @code_warntype foo(zeros(3,4))

foo(a::Array{T,N} where T ) where N = Val(N)

I get the same result if I replace Val(N) with Val{N}(). Both are inferrable.

  • Could I safely use Val(N) instead of Val{N}() in my codes?

  • If yes, I would like to know why the first example is providing different outputs.


Let me attempt an answer. Calling @code_warntype on Val(1) treats Val as the “main” function and 1 as the “input”. Technically, the Val function is not type stable. However, inside another function when using Val(N) where N is a compile-time constant, e.g. a type parameter or the length of a tuple, inter-procedural constant propagation ( kicks in making Val(N) infer nicely. Note that the input to the function Val when tested directly with @code_warntype is not treated as a constant in the above case, hence the type instability.


I see, inter-procedural constant propagation is the key. Thanks for the answer!

I’m definitely not an expert in this area, but I think that, at least in recent julia versions, precisely thanks to constant propagation, using Val is less of a necessity.

For example, the following infers just fine:

julia> using Test

julia> f(v::AbstractArray{T, N}) where {T, N} = ntuple(log, N)
f (generic function with 1 method)

julia> @inferred f([1 2; 3 4])
(0.0, 0.6931471805599453)

So I’m not completely sure that the performance tips here to use Val{N}() for this scenario are still relevant. (Of course I could be wrong and there could be more complex scenarios in which using Val matters.)