Thanks, all. BTW, I realize the topic has been discussed often but I was missing the right keywords to search for. Now that I know what to look for, these old threads were very relevant and interesting.
The solutions are the same – either stick to OOP way of thinking about inheritance and use macros to work around Julia’s “limitations”, or adopt the composition approach suggested by @lmiq and @Sukera with the Common
struct (perhaps renamed PetState
or PetData
) containing all the info that functions dispatching on abstract Pet
need to be aware of.
There is still the slightly annoying book-keeping issue of accessing fields through nested getproperty()
calls e.g.
struct Dog <: Pet
data::PetData
end
d = Dog(PetData("Fido"))
d.name # Error
d.data.name # returns "Fido"
But looks like Lazy.@forward can help save time implementing a bunch of pass-through methods like get_name(pet::Pet) = pet.data.name
. Can probably even overload getproperty()
but that could come with some performance issues.