You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@nospecialize does not work when attached to unused parameters in a function signature (i.e. those named _).
More generally, unused parameters, unless both named and used with @no_specialize will generate specializations even if they are unable to affect the result of a method invocation.
Description
Consider the following three function definitions
f(a, b, _) = a + b /2f(1, 2, 3)
f(1, 2, 3.0)
f(1, 2, 3.0+ im)
g(a, b, @nospecialize _) = a + b /2g(1, 2, 3)
g(1, 2, 3.0)
g(1, 2, 3.0+ im)
h(a, b, @nospecialize _x) = a + b /2h(1, 2, 3)
h(1, 2, 3.0)
h(1, 2, 3.0+ im)
If we inspect the specializations for these methods, we find the following
julia> Base.specializations(methods(f)[1])
Base.MethodSpecializations(svec(MethodInstance for f(::Int64, ::Int64, ::Int64), MethodInstance for f(::Int64, ::Int64, ::Float64),
MethodInstance for f(::Int64, ::Int64, ::ComplexF64), nothing, nothing, nothing, nothing))
julia> Base.specializations(methods(g)[1])
Base.MethodSpecializations(svec(MethodInstance for g(::Int64, ::Int64, ::Int64), MethodInstance for g(::Int64, ::Int64, ::Float64),
MethodInstance for g(::Int64, ::Int64, ::ComplexF64), nothing, nothing, nothing, nothing))
julia> Base.specializations(methods(h)[1])
Base.MethodSpecializations(MethodInstance for h(::Int64, ::Int64, ::Any))
In short, despite the throwaway parameter being unused, the functions specialize on it regardless, even if @nospecialize is used, unless the throwaway parameter is given a name.
This leads to the generation of a lot of useless code, potentially significantly increasing compile times. As a more realistic example, closer to how I ran across this issue in my code while trying to reduce precompilation times, consider the following code which defines an interface:
# Interface definitionabstract type Model endfunctiondo_something(::T, _, _) where {T <:Model}
throw(ArgumentError("$(nameof(T)) has not implemented the `do_something` interface!"))
end# Model1 uses both parametersstruct Model1 <:Modelendfunctiondo_something(::Model1, param1, param2)
return param1 + param2
end# Model2 uses only one paramstruct Model2 <:Model
val::Float64endfunctiondo_something(m::Model2, param1, _)
return param1 * m.val
end# Model3 does not implement the interfacestruct Model3 <:Modelendtrydo_something(Model3(), 1.0, 2.0)
catchendtrydo_something(Model3(), 1.0, 2)
catchenddo_something(Model1(), 1.0, 2.0)
do_something(Model1(), 1.0, 2)
do_something(Model2(5.0), 1.0, 2.0)
do_something(Model2(5.0), 1.0, 2)
@showlength(Base.specializations(methods(do_something)[1])) # 2@showlength(Base.specializations(methods(do_something)[2])) # 2@showlength(Base.specializations(methods(do_something)[2])) # 2
Ideally, neither the fallback method of do_something nor the one taking a Model2 would specialize on their unused parameters. However, each generates two specializations. This can be fixed by using @no_specialize and a named parameter,
but is quite ugly and pretty advanced. It can also lead to superfluous IDE tooling warnings about unused parameters.
Versions
@mcabbott tested this and found that it occurs on both v1.10 and nightly. I have found it to also occur on v1.11.1
The text was updated successfully, but these errors were encountered:
Summary
@nospecialize
does not work when attached to unused parameters in a function signature (i.e. those named_
).More generally, unused parameters, unless both named and used with
@no_specialize
will generate specializations even if they are unable to affect the result of a method invocation.Description
Consider the following three function definitions
If we inspect the specializations for these methods, we find the following
In short, despite the throwaway parameter being unused, the functions specialize on it regardless, even if
@nospecialize
is used, unless the throwaway parameter is given a name.This leads to the generation of a lot of useless code, potentially significantly increasing compile times. As a more realistic example, closer to how I ran across this issue in my code while trying to reduce precompilation times, consider the following code which defines an interface:
Ideally, neither the fallback method of
do_something
nor the one taking aModel2
would specialize on their unused parameters. However, each generates two specializations. This can be fixed by using @no_specialize and a named parameter,but is quite ugly and pretty advanced. It can also lead to superfluous IDE tooling warnings about unused parameters.
Versions
@mcabbott tested this and found that it occurs on both v1.10 and nightly. I have found it to also occur on v1.11.1
The text was updated successfully, but these errors were encountered: