It’s not quite as convenient, but you can use nothing as the default and check for it:
julia> function g(a; b=nothing)
if b === nothing
b = ntuple(_ -> a, a)
end
b
end
g (generic function with 1 method)
julia> g(2)
(2, 2)
julia> g(2, b=(3, 4))
(3, 4)
The something function can also make this easier:
julia> g(a; b=nothing) = something(b, ntuple(_ -> a, a))
g (generic function with 1 method)
julia> g(2)
(2, 2)
julia> g(2, b=(3, 4))
(3, 4)
help?> something
search: something
something(x, y...)
Return the first value in the arguments which is not equal to nothing, if any. Otherwise throw an error.
Arguments of type Some are unwrapped.
The reason this doesn’t work is that a is a value that is not known until runtime.
Apparently, you cannot depend a type signature (of b) on the runtime value of a.
The following would work:
julia> function g(::Val{a}, b::NTuple{a, Int64} = Tuple(repeat([a], a))) where a
return b
end
g (generic function with 2 methods)
julia> g(Val(2))
(2, 2)
julia> g(Val(3))
(3, 3, 3)
Of course, you can also do:
julia> function g2(a)
Tuple(repeat([a], a))
end
g2 (generic function with 1 method)
julia> g2(2)
(2, 2)
julia> g2(3)
(3, 3, 3)
julia> @code_warntype g2(3)
Variables
#self#::Core.Const(g2)
a::Int64
Body::Tuple{Vararg{Int64, N} where N}
1 ─ %1 = Base.vect(a)::Vector{Int64}
│ %2 = Main.repeat(%1, a)::Vector{Int64}
│ %3 = Main.Tuple(%2)::Tuple{Vararg{Int64, N} where N}
└── return %3
As @code_warntype displays, the function is type instable since the output type depends on the value of a. Such a pattern should be avoided in performance critical code.