obj GenericKeyedList = GenericKeyedElem* ops: Add(l:GenericKeyedList, e:GenericKeyedElem)->(l':GenericKeyedList), Del(l:GenericKeyedList, k:GenericKey)->(l':GenericKeyedList), Find(l:GenericKeyedList, k:GenericKey)->(e:GenericKeyedElem); end; obj GenericKeyedElem = k:GenericKey and d:GenericData; obj GenericKey = string; obj GenericData; obj IntKeyedList < GenericKeyedList where: GenericKeyedElem = IntKeyedElem; end; obj IntKeyedElem < GenericKeyedElem where: GenericData = integer; end; obj GenericList = GenericElem* ops: Add(l:GenericList, e:GenericElem)->(l':GenericList), Del(GenericList, k:GenericKey)->(l':GenericList), Find(l:GenericList, k:GenericKey)->(e:GenericElem); end; obj GenericElem; obj IntList < GenericList where: GenericElem = IntElem; end; obj IntElem < GenericElem = i:integer; (* * * The following discussion is partially incorrect in the statement that * generic op instantiation is necessary for IntListAlt, but not for IntList. * The reason that it is incorrect is that Add(IntList(1,2,3), 4) will not work * in the 2nd arg without generic op instantiation, since subtype polymorphism * cannot be invoked to resolve the type of 4 with type GenericElem, since the * latter is simply an opaque type with no direct relationship to integer, even * if IntElem < GenericElem. That is, 4 will not automatically retract to * IntElem in the call, so there is no way to get up to the GenericElem. * Hence, generic op instantiation is in fact necessary in all cases, not just * where something is instantiated directly as an atomic type. * * PARTIALLY INCORRECT DISCUSSION STARTS HERE. * Alternative def of IntList, where GenericElem is instantiated directly as * integer rather than indirectly through GenericElem. The important issue * here is that we rely on the generic instantiation of ops to define overloads * for each of the three GenericList member operations. Without this ops * instantiation, the overload Add(IntList, integer)->IntList, e.g., would not * otherwise be defined, where "otherwise" is subtype polymorphism. Hence, * without generic ops instantiation, the call Add(IntListAlt(1,2,3), 4) would * fail on the second arg. * * In the earlier def of IntList, generic op instantiation is not necessary, * since the subtype polymorphism enabled by IntElem < GenericElem * automatically renders Aad(IntList, IntElem)->IntList defined, and since * IntElem is integer, the call the call Add(IntList(1,2,3), 4) works fine. *) obj IntListAlt < GenericList where: GenericElem = integer; end; op Add(l:GenericList, e:GenericElem)->(l':GenericList); op Add(l:GenericList, e:IntElem)->(l':GenericList); (* op Add(l:GenericList, e:integer)->(l':GenericList); *) (* Once generic op instantiation is working, the preceding 3 defs should * not be necessary. *) op main(il: IntList, ila:IntListAlt, ge:GenericElem, ie:IntElem) = ( Add(il, ie); Add(ila, ie); Add(ila, ge); Add(il, 4); Add(ila, 4); );