Exactly what functions get compiled versions for specialized types?

question

#1

If I define a function like:

f(x) = x + 1

and then call it, f(1), I’ll get a compiled version that is specialized for Ints. Does this apply for all callables?

For example, if I define a closure, f = (x -> x + a), where a is a variable defined in the surrounding environment, will f(1) get “compiled”? What exactly does it mean here?

Finally, what about callable types? I take this example from the docs,

julia> struct Polynomial{R}
           coeffs::Vector{R}
       end

julia> function (p::Polynomial)(x)
           v = p.coeffs[end]
           for i = (length(p.coeffs)-1):-1:1
               v = v*x + p.coeffs[i]
           end
           return v
       end

julia> p = Polynomial([1,10,100])
Polynomial{Int64}([1, 10, 100])

julia> p(3)
931

Does p(3) use a compiled version? What if I create another polynomial, q = Polynomial([10,14,1]), and make another call q(4). This triggers a new compiled function? Or does it use the same compiled version created before?

Finally, what about constructors?

As you can see, I am a bit confused about this.


#2

Since the types match, the same compiled version.

Same applies to constructors. All that matters is the type signature.


#3

@Tamas_Papp What about closures? Is there a part of the docs explaining this that I am missing? Thanks!


#4

A closure is similar to a call overloaded struct where the closed over variables are the fields.


#5

I don’t think that’s true in general. It seems that the compiler does not specialize over functions and over types, unless the arguments are typed via parametric where syntax. There might be more to it. I wrote some code to inspect the specializations.

One gotcha is that the compiler will always perform inference using the leaf types, even when it does not generate specialized code for it.