How to check for unwanted specialization and how to prevent specialization?

Take this simple function: f(::Any) = 7. Its only argument is never used, so ideally Julia wouldn’t ever have to specialize for it, to prevent unnecessary compilation latency. The manual suggests using @nospecialize and Base.@nospecializeinfer to prevent unnecessary specialization, however I’m not sure if these macros actually have any effect. It seems like a specialization is being computed for each new argument type despite using these macros:

julia> Base.@nospecializeinfer f(@nospecialize _) = 7
f (generic function with 1 method)

julia> f(:r)
7

julia> f(3)
7

julia> f(false)
7

julia> collect(only(methods(f)).specializations)
7-element Vector{Any}:
 MethodInstance for f(::Symbol)
 MethodInstance for f(::Int64)
 MethodInstance for f(::Bool)
 nothing
 nothing
 nothing
 nothing

How to prevent this unnecessary specialization, and how to be able to tell that there’s no unnecessary specialization?

1 Like

Replacing _ with x avoided specialization for me (and only @nospecialize was required) Seems like a bug?

julia> f(@nospecialize _) = 7
f (generic function with 1 method)

julia> Base.specializations(@which f(1))
Base.MethodSpecializations(MethodInstance for f(::Int64))

julia> h(@nospecialize x) = 7
h (generic function with 1 method)

julia> Base.specializations(@which h(1))
Base.MethodSpecializations(MethodInstance for h(::Any))
3 Likes

See optimizer: `@nospecialize` annotation doesn't work when applied to unnamed argument · Issue #44428 · JuliaLang/julia · GitHub. I also think there is an issue/feature request about having _ variables be @nospecialized by default, but can’t find it now.

5 Likes