Merging composite types - multiple inheritance of fields/mixins


#1

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?


#2

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.


#3

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.


#4

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.