Is there a Julian way to combine types generically or a design pattern that achieves the goal?

Add to my initial post: perhaps following the “only one path of nesting” restriction and using @StefanKarpinski’s suggestion here would imply a partial solution whereby each next layer of packing is done by defining an abstract type and its interface, where the abstract types nest in something like AT1 <: AT2 <: AT3 <: ... and each concrete type breaks off as such:

AT1 <: AT2 <: AT3 
 |      |      |
CT3    CT2    CT1

(vertical | also indicates <: but where the LHS is a concrete type and RHS is abstract).

E.g. CT1 has the fewest fields and thus subtypes the broadest abstract type. CT2 is-a AT2 and therefore is-a AT3, and therefore has all the fields that CT1 has plus whatever else it has, except that the has-a relationships are encoded as functions on the ATs.

For example

@auto_generate abstract AT3
    field1::Float64
    field2::Int64
end
#would turn into something like

abstract AT3
function get_field1(x::AT3)
    x.field1
end #or similar
function get_field2(x::AT3)
    x.field2
end #or similar

#So then given
immutable CT1 <: AT3
    field1::Float64
    field2::Int64
end
#We'd already have effectively function get_field1(x::CT1) = x.field1

#Then we'd also need something like

@auto_generate_nested abstract AT2 <: AT3
    at3::AT3
end
#More magic here...somehow this does something like
function get_field1(x::AT2)
    get_field1(x.[get first field subtyping AT3])
end

#So then 
immutable CT2 <: AT2
    ct1::CT1
    field3::String
end
#Would already have function get_field1(x::CT2) = get_field1(x.ct1)
#and so on for CT3, AT1, etc.

Realize this is quite clunky (and skips issues of well-defined-ness in implementation and also of ensuring consistency among field types…though I think these could both be handled by restricting the functionality sufficiently); it’s certainly not what I think should prevail. Just trying to push the discussion forward.