(* * Herein we investigate what happens if a parent object is also a union. What * we care about is if having a union-valued parent conflicts in any way with * defining inheritance in terms of union. The possible conflicts are in the * areas of defining the overloaded isa operator, and making sure that auto * injection of union values can be done without requiring the children of * union-valued parents not to have any of the union-type alts as there values. *) obj Parent = i:integer or s:string; obj Child < Parent = i:integer or s:string; obj Child2 < Parent = x:(i:integer or s:string); obj Other = i:integer or s:string and x:real or c:Child; obj Other2 = i:integer or o:(s:string and x:real) or c:Child; op main(p:Parent, c:Child, c2:Child2, o:Other, o2:Other2) = ( p ?. i; -- OK: checks if p's union val is integer c ?. i; -- ERROR: c is not a union, i.e., it's a tuple of -- (integer or string) and (integer or string) -- with an anonymous second tuple field c.x ?. i; -- ERRORS: x is not a component of c -- left operand of is is not a union c2.x ?. i; -- OK: checks if c2's second tuple field is integer -- this works where c ?. i did not because we've -- given a name to the previously anonymous second -- tuple field c2.y ?. i; -- ERRORS: x is not a component of c -- left operand of is is not a union o ?. i; -- OK: checks if o's union val is integer o ?. s; -- ERROR: s is not a tag of o, since o is a union of -- (integer or (string and real) or Child), -- with an anonymous second union field o ?. c; -- OK: checks if o's union val is Child o2 ?. i; -- OK: checks if o2's union val is integer o2 ?. o; -- OK: checks if o2's union val is (string and real); -- this works where o ?. s did not because we've -- given a name to the previously anonymous second -- union field o2.o ?. i; -- ERROR: o2.o is not a union (it's a tuple) o2.o.s; -- OK: accesses string component of o2.o -- TODO: add all possible checks for the overload of ?. as a subtype -- checking op as opposed to its use above as a union checking op );