This has been talked about a lot before - the lack of mixin functionality in julia.
But I’ve been thinking about mixins a lot – for merging existing composite types to balance modularity with simplicity when using lots of micro-modules to assemble complex models.
Heres a toy example. My real examples have a lot more parameters – that’s the reason for avoiding just writing them out again, as would probably be the best idea here:
struct FirstStruct{T}
par1::T
par2::Float64
end
struct SecondStruct{T}
par3::T
par4::Int
end
@mergecomposite CompositeStruct FirstStruct SecondStruct
Which generates:
struct CompositeStruct{T1, t2}
par1::T1
par2::Float64
par3::T2
par4::Int
end
First I’m wondering about this as a design pattern, and how people are doing mixin patterns in 2018, if they are at all? Any reasons this is not a good idea?
AFAIK the consensus is that in Julia you should prefer containment. Search for “containment inheritance” for a lot of opinions about the topic in general. A macro could construct
struct CompositeStruct{T1, T2}
a::T1
b::T2
end
but IMO it is hardly worth the loss of transparency. The key part is implementing functionality of elements, see eg Lazy.@forward to automate this.
Mostly I’m using totally parametric types and no methods as these are model parameters - there is only ever one set. So Lazy.@forward isn’t necessary. (I’m writing all the sub-modules so I get to make that decision). Any inheritance or methods would be using holy traits, like “has field param1”
This combination seems to remove a lot of the arguments for composition over inheritance, and the arguments against containment become more important: data structures can get too complex and nested.
But I can see the case fo keeping the modularity clear and explicit in the data structures. Guess I’ll have to try both and see how it feels.
For anyone researching this issue later on: after going with containment for a day I’m beginning to think that even thinking about doing things the way I originally suggested is probably a code smell. I solved so many issues just using containment. Flattening nested fields isn’t that hard either if you really need it for something
A simple @def macro for inserting repeared non-parametrically typed fields is a useful DRY mixin pattern and probably as far as mixins should ever go.