Passing abstract structs to a function

Hello, I’m trying to write a solver library for a very specific machine learning problem and I have a function that errors in runtime and I really don’t understand what exactly is wrong.

In particular, the function that errors is:

function risk(S::Vector{Sample}, γ::Vector{Function})
	return ( S .|> (s -> loss(s, γ)) |> sum ) / size(S)[1]
end

Where:

function loss(s::Sample, γ::Vector{Function})
	v = collect(Iterators.flatten([g(y) for (g, y) in zip(γ, s.Y)]))
	return real(dot(v, s.R * v) + 2 * real(dot(v, s.r)) + s.c)
end

And Sample is defined as:

struct Sample{T <: Number}
	Y::Vector{Vector{T}}
	R::Matrix{T}
	r::Vector{T}
	c::T
end

The error I get reads:

MethodError: no method matching risk(::Vector{Sample{Float64}}, ::Vector{Function})

Closest candidates are:
  risk(!Matched::Vector{Sample}, ::Vector{Function})

This doesn’t make sense to me, as Vector{Sample{Float64}} is a subtype of Vector{Sample}. Moreover calling loss on a single sample works just fine. Additionally, calling risk(Vector{Sample}(S), \gamma} also works, which is honestly baffling, as I am essentially casting to a more generic type.

Also, I am declaring Sample as parametrised by a Number since I need to handle both real and complex valued samples.

I feel that intuitively, there’s nothing wrong with my code, after all, Julia main advertised feature is multiple dispatch, i.e the ability to write generic functions and structs. But then again, I am pretty new to the language, so I must be missing a piece of the puzzle here.

It is not (see documentation and other discussions here).
You need to explicitly specify the type as Vector{<:Sample} (and maybe the second type as Vector{<:Function}).

5 Likes

Indeed, this solves the issue.
Thanks a lot.