Is it good to include a function in my struct?

I have a struct which has a field referring to a function, which is used as following.

struct myT
f::Function
end

function Base.getindex(foo::myT, i)::Float64
    foo.f(...)
end 

I noticed that code_warntype shows

│   %50 = Base.getproperty(ts, :fn)::Function
│   %51 = (%50)(p)::Any
│   %52 = Base.getproperty(ts, :fval)::Dict{NTuple{15, Int64}, Float64}
│         Base.setindex!(%52, %51, I)
│   %54 = Base.convert(%3, %51)::Any
│   %55 = Core.typeassert(%54, %3)::Float64

There are a few Any. I don’t know if this means the compiler cannot determine the return type of the function f in compile time. I added Float64 as the return type, but it seems only to do a type conversion at the end, and does not tell the compiler the information of the function.

I’m curious if this would affect the performance. Thanks.

Function is an abstract type. Each function has its own type. If you want your struct to contain a function, for performance reasons use a type parameter:

struct myT{F<:Function}
    f::F
end
8 Likes

Thank you. I have a related question. I have another type which depends on the parametric type myT{...}.

Struct SMat{valT}
   t::myT
   
   val::valT
   function SMat(t::myT{valT, ....}, ....) where valT
       new{valT}(t, val)
   end
end

The above type can get the parameter of myT, but I also want myT to be concrete. I tried several ways but all failed.

Is there a clear introduction to julia’s template system? I feel very confused.

Thank you.

There are two options, either you parameterize the parameter of the inner struct:

struct SMat{valT,F<:Function}
    t::myT{F}
    val::valT
end

or, if that starts to become too complicated, you can parameterize the whole field

struct SMat{valT, T<:myT}
    t::T
    val::valT
end

I think I would like to go with the 2nd approach, but the issue is that the type valT should be inferred from the type of t, which is myT{valT, ...}. If I parametrize the whole field, that information seems hidden. Of course I can provide it explicitly, but I’m curious if I can make the compiler infer this information.

I’m not sure if I understand, but if valT has the same type of t you can use

struct SMat{T<:myT}
    t::T
    val::T
end

of if it shares some type parameter with t, you could use

struct SMat{valT, T}
    t::T{ValT}
    val::valT
end
2 Likes

The type of t is quite complicated. Maybe I didn’t design it well at the beginning. I decided to specify valT directly to SMat.

Thanks a lot for your help!

1 Like