I recently learned about the “delegation” design pattern, and that there are numerous ways one could implement this within Julia. For example, the famous @forward macro makes it easy to “delegate” a set of methods meant for one struct to another wrapper struct.
Is there a canonical way to do the same for functions that work on a vector of structs? For example, suppose I have something like
struct foo
val::Int
end
and I want to extend the Base.findfirst() method to a vector of foos by looking at the val member.
You could certainly overload findfirst this way, but it seems like a confusing pun on the meaning of findfirst? Or you could define a whole bunch of methods like == and so forth that you want to work for comparing a struct foo to numbers?
Seems a lot clearer to just write things like findfirst(==(foo(3)), array_of_foos), though, unless struct foo is supposed to represent a kind of numbrer?
but it seems like a confusing pun on the meaning of findfirst ?
Yes, this was a bad example on my part. Let me try another example (using one your packages) that might better motivate my question. It may be that there’s a simple “multiple dispatch solution” to this as well (if so, great!) but I’m having trouble thinking through it…
Suppose I was building a system matrix with GeometryPrimitives.jl. The package exports an abstract Shape, along with various shape subtypes, like Cylinder, Cube, etc. Importantly, it also exports some useful functions, like KDTree, and even overloads findfirst to operate on a vector of Shape types.
Now suppose I wanted to create a “wrapper” type that had all the attributes of existing shapes, but also had a permittivity field (ε) that I could use to populate my system matrix (or maybe I include various other “material parameters”).
This seems like a prime use case for the “delegation design pattern” (from what I’ve read), as I could simply “forward” all of the existing infrastructure to my new wrapper type. I’m wondering if there’s a clean way to do this with the methods that act on vectors of types too.
But perhaps there’s an even simpler, more idiomatic way to accomplish this? Thanks!
In that particular case, Shape is an abstract type, so one approach would be to simply declare a subtype that adds metadata, but contains another shape and delegates to it for geometric primitives. Then it will work fine with array methods.
I would also say that the KDTree implementation in that package might be better off returning an index into an array of shapes, so that you can simply store metadata about each shape in another array. In general, I think that this package needs some re-working and the difficulty of using it with metadata is a symptom of that.