Or maybe a more general macro that lets you define a single default argument in any position.
So that
@default_arg foo(x = a, y, z) = ...
expands into
foo(y, z) = foo(a, y, z)
foo(x, y, z) = ...
macro default_arg(ex)
(ex.head === :function || ex.head === :(=)) || throw(ArgumentError("Invalid expression"))
call = ex.args[1]
call1 = copy(call)
call2 = copy(call1)
Nargs = length(call.args)
for i in 2:Nargs
arg = call.args[i]
if Meta.isexpr(arg, :kw, 2)
call.args[i] = arg.args[1]
deleteat!(call1.args, i)
call2.args[i] = arg.args[2]
break
end
end
q = quote
$ex
$call1 = $call2
end
esc(q)
end
Yields:
julia> @macroexpand @default_arg function my_func(rng = default_rng(), x, y, z)
out = rand(rng)*x + y/z
end
quote
#= REPL[33]:17 =#
function my_func(rng, x, y, z)
#= REPL[39]:1 =#
#= REPL[39]:2 =#
out = rand(rng) * x + y / z
end
#= REPL[33]:18 =#
my_func(x, y, z) = my_func(default_rng(), x, y, z)
end
julia> @default_arg function my_func(rng = default_rng(), x, y, z)
out = rand(rng)*x + y/z
end
my_func (generic function with 2 methods)
julia> my_func(1.2, 2.3, 4.5)
1.0098752663124524