Thanks. @platawiec’s solution does partially solves my problem. I fear my attempt to construct a mwe made it unclear where the performance aspect lies (or maybe I misunderstood something).
A bit more elaborate example: I want the first argument to determine which arithmetic my algorithm should run, and default to Complex128. I also have some kwargs.
So, a and b should be the same:
a=myfun(3.0)
b=myfun(Complex128,3.0)
This is how I tried to achieve this (drastically simplified from my application, dont pay so much attention to the contents of the function):
myfun(x::Float64;kwargs...)=myfun(Complex128,x;kwargs...)
function myfun(::Type{T_arithmetic},x::Float64;
x1::Vector{<:Number}=ones(T_arithmetic,2)
) where T_arithmetic<:Number
z=zeros(T_arithmetic,2)
z[1]=x;
z+=x1; # no inplace
return z;
end
The call myfun(Complex128,3.0)
is type stable according to (@code_warntype
), but myfun(3.0)
is not. If I replace <:Number
with T_arithmetic
in the kwarg it becomes type-stable. However, I want it to be real vector. If I replace <:Number
with Vector{real(T_arithmetic)}
I get the same error as above.
This type instability can cause a performance penalty, right?
Type stability check:
julia> @code_warntype(myfun(3.0))
Variables:
#self#::#myfun
x::Float64
Body:
begin
return $(Expr(:invoke, MethodInstance for #myfun#1(::Array{Any,1}, ::Function, ::Float64), :(Main.#myfun#1), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0))), :(#self#), :(x)))
end::Any
julia> @code_warntype(myfun(Complex128,3.0))
Variables:
#self# <optimized out>
#temp# <optimized out>
x::Float64
z::Array{Complex{Float64},1}
Body:
begin
SSAValue(1) = $(Expr(:invoke, MethodInstance for fill!(::Array{Complex{Float64},1}, ::Complex{Float64}), :(Base.fill!), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Complex{Float64},1}, svec(Any, Int64), Array{Complex{Float64},1}, 0, 2, 0))), :($(Expr(:new, Complex{Float64}, :((Base.sitofp)(Float64, 1)::Float64), :((Base.sitofp)(Float64, 0)::Float64))))))
$(Expr(:inbounds, false))
# meta: location /home/jarl/.julia/v0.6/NonlinearEigenproblems/src/mynewton.jl #myfun#2 7
z::Array{Complex{Float64},1} = $(Expr(:invoke, MethodInstance for fill!(::Array{Complex{Float64},1}, ::Complex{Float64}), :(Base.fill!), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Complex{Float64},1}, svec(Any, Int64), Array{Complex{Float64},1}, 0, 2, 0))), :($(Expr(:new, Complex{Float64}, :((Base.sitofp)(Float64, 0)::Float64), :((Base.sitofp)(Float64, 0)::Float64)))))) # line 8:
(Base.arrayset)(z::Array{Complex{Float64},1}, $(Expr(:new, Complex{Float64}, :(x), :((Base.sitofp)(Float64, 0)::Float64))), 1)::Array{Complex{Float64},1} # line 9:
z::Array{Complex{Float64},1} = $(Expr(:invoke, MethodInstance for +(::Array{Complex{Float64},1}, ::Array{Complex{Float64},1}), :(Main.+), :(z), SSAValue(1)))
# meta: pop location
$(Expr(:inbounds, :pop))
return z::Array{Complex{Float64},1}
end::Array{Complex{Float64},1}