When should we use `@nospecialize`?

The manual is sketchy about the use of @nospecialize (maybe it is still WIP?). I gather it is a necessary optimisation to avoid overburdening the dispatch tables. Is the end user advised to use this macro in some specific circumstance or coding pattern?


You can use it when a function is called multiple times with different argument types, compiling that function is expensive but specialising on argument types does not have a significant impact on run-time performance.

For an example in the wild: https://github.com/ZacLN/CSTParser.jl/blob/20b6eac1ec7db62ced97eadb09f0d4e9653db97a/src/CSTParser.jl#L178 (::ANY is the old @nospecialize).


what does that really mean? @nospecialize makes it faster to dispatch if I don’t specialize the function according the its argument types?

Is that what you are trying to say?


@nospecialize makes julia compile a generic version of the function that works for all input types (so it only has to be compiled once). Normally, Julia compiles a separate version of the function for any combination of input types. This code will be more specialized and faster since it uses all the type information but in some cases, you rather avoid the extra compilation.


Thank you very much.! basically this is hint to the compiler to avoid compilation for specific types.

I’m confused… in my understanding, only one specified version of function would be compiled on the first time being called with concrete inputs. That said, all other possible combinations of input types should be irrelevant until being explicitly used in later calls.

To be more precise, I mean the method f(x::AbstractFloat) = 2x is not compiled to anything, until a call like f(1.0) is made, where the specified method f(::Float64) is created and compiled. That said, all other specified versions like f(::Float32) are not yet created and compiled.

Is it true? if it is, I don’t see the point of defining like f(@nospecialize x::AbstractFloat) = 2x (that means I must have something wrong)

Please correct me. thanks.

Yes it is true.

It is for cases where you don’t want to compile different versions of f(::Float64), f(::Float32) etc, but only have one version that works for all input types.


how could it be possible? even for a simple method like f(x::AbstractFloat) = 2x, the implementations of 2x would be different for various floating types of x. What is the nature of that “one version”? It could not be a compiled machine code… :dizzy_face:

In the end, everything that runs is “machine code” but yes, it will be more dynamic code, getting help from the julia runtime.