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 AT
s.
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.