Creating an abstract type as a wrapper for types different functions that serve the same purpose

I’m trying to create an abstract type that is a superclass (called Kernel) several different of functions, each a subclass of Kernel --i.e.

abstract type Kernel end

struct ExponentialKernel <: Kernel
    ExponentialKernel(rate::Number, x::Number) = exp(-1*rate*x)
end


struct GaussianKernel <: Kernel
    GaussianKernel(sigma::Number, x::Number) = (1.0/(sigma*sqrt(2*pi))) * exp((-1*x^2)/(2*sigma^2)
end

...

and so on.

When I use what I have above, it works in the sense that when I call ExpKernel(a,b) I get the right value, but when I try to pass these kernel objects to a different constructor, like

mutable struct Model
    kernel::T where {T <: Kernel}    

    Model(kernel) = new(kernel) 
end

When I call Model(ExpKernel) I get the error

ERROR: MethodError: Cannot `convert` an object of type Type{ExpKernel} to an object of type Kernel

Is there something I’m missing about types here?

You can either do

struct Model
    kernel::Kernel
end

or

struct Model{T <: Kernel}
    kernel::T
end

In the first one, Model does not have information in its type about which kernel it stores. This will probably lead to a performance penalty for you, but that can’t be said for sure without knowing the context.
The second one is a parametric type, parameterized by which kernel type it stores. Note that I made the type immutable. I expect that’s probably what you want also, as I don’t expect there is value in a mutable kernel (I could be wrong), and mutability also often comes with a performance penalty.


Although it was not part of the question:

struct ExponentialKernel <: Kernel
    ExponentialKernel(rate::Number, x::Number) = exp(-1*rate*x)
end

I don’t think what you wrote does what you want:

julia> ExponentialKernel(5, 5)
1.3887943864964021e-11
3 Likes