Type instability using interpolation as field of struct

My application has a construct equivalent to the following MWE

using Interpolations

struct MyStruct{T<:Real, IT<:AbstractInterpolation{T,1}}
    x::Array{T,1}
    y::Array{T,1}
    itp::IT
end

MyStruct(x::Array{T,1},y::Array{T,1}) where T = MyStruct{T,AbstractInterpolation{T,1}}(x,y,LinearInterpolation(x,y))

x = collect(1.0:50.0)
y = randn(50)
m = MyStruct(x,y)

f(m::MyStruct{T, AbstractInterpolation{T,1}}, x::T) where T<:Real = m.itp(x)

for which calling

@code_warntype f(m,1.0) 

gives Any as the return type. Is there some way to rewrite this so that the return type can be correctly inferred as T (i.e. Float64 in this case)?

Your constructor and method definitions are a bit odd (over specified).

Using

MyStruct(x::Array{T,1}, y::Array{T,1}) where T = MyStruct(x,y,LinearInterpolation(x,y))

f(m::MyStruct{T}, x::T) where T<:Real = m.itp(x)

and things are ok.

Why did you shove the AbstractInterpolation{T,1} part into the constructor call?

Proximally, the original struct has two parametric type parameters and I assumed you needed to specify both of them in the constructor. Ultimately, I still don’t have a good grasp of how to use Julia’s parametric type system (rather embarrassingly given the cake symbol I just noticed next to my name)

If the parameter can be determined from the inputs there is no need to specify it.

julia> struct S{T}
           x::T
       end

julia> S(2)
S{Int64}(2)

Ok, that is useful to know. In this case, the constructor is also doing the extra work of doing the interpolation. The thing that confuses me is that if I do @code_warntype m.itp(x), that is fine, but f(m,x) is not even when the type information is present in m; I think this is quite similar to the question from Type instability if function inside a struct is run inside another function , and my original solution was an attempt to emulate the accepted solution from that question

Sure but it isn’t really anything different from

julia> struct S2{T, P}
           x::T
           y::P
       end

julia> S2(x) = S2(x, sin(x))
S2

julia> S2(1)
S2{Int64,Float64}(1, 0.8414709848078965)

The problem in your example was that there was “bad” type information in m. What was put as IT was AbstractInterpolation which the compiler cannot reason about. What we wanted in there was the concrete type of the interpolation object that we created.

Thanks - I really appreciate the example; a good Julia birthday present