obj Elem; obj Stack = e:Elem*; -- obj IntStack < Stack where: Elem = IntElem; end; -- Next def replaces preceding to give semantics of not-yet-implemented generic -- instantiation. obj IntStack = e:IntElem* and;(*< Stack where: Elem = IntElem; end;*) obj IntElem < Elem = integer; obj StrStack < Stack where: Elem = StrElem; end; obj StrElem < Elem = string; op Push(Stack,Elem)->Stack; op Push(IntStack,IntElem)->IntStack; op Push(StrStack,StrElem)->IntStack; op Pop(Stack)->Elem; op Pop(ist:IntStack)->IntElem = ist.e[1]; op Pop(StrStack)->StrElem; op main(s:Stack,ist:IntStack,i:integer,ie:IntElem,se:StrElem) = ( Push(s, i); (* ERROR, since int !< Elem, and T={T} cant help *) Push(ist,se); (* ERROR, per new superflash rule. *) Push(ist,i); (* Works by T = {T} rule. *) Push(ist,10); (* Ibid. *) Push(s,ie); (* Works, since IntElem < Elem *) ); (* * The superflash above effectively trashes the entire discussion that follows * (starting in the next comment block). We'll leave the discussion for * posterity. With the new rule that generic instantiations are not subtypes, * the potentially problematic line just above, viz. Push(ist,StrElem("abc")), * will no longer type check. The reason it type checks without this new rule * is that IntStack is still < Stack, so that when the resolution to * Push_IntStack_IntElem fails, we can look at Push_Stack_Elem, via subtype * poly. HOWEVER, the new rule says that subtype poly is out now. Hence, * since there is no explicit def of Push(IntStack, StrElem) or Push(IntStack, * Elem), there can be no resolution of the problematic call. Bitchin again. * * One way to look at the new rule (gen instantiations are not subtypes) is * that it implements automatically, and in the right places, the notion of * strict inheritance introduced below, but below required invention of a new * operator. Can I have one more bitchin, please? *) (* * * TRASHED DISCUSSION FOLLOWS. * * Here's an interesting position we might be finding ourselves in. If both * int and string are subtypes of Elem, then we get in the situation where the * following might be type safe, even though we dont want it to be: * * Push(IntStack(nil), "abc") * * The reason it might be type safe is as follows: since IntStackStrElem *) ); (* * But, if we really want to solve the problem "properly", it's on to 4.0, in * which, among other things, we'll have the notion of strict inheritance, with * a new symbol to boot. Here's the deal ... . Normally, if T1 < T2, then * values of type T1 can be bound to vars of T2, but not vice versa (of * course). With strict inheritance, which we'll denote T1 StrictlyIntStack; (* This op should be automatically def'd by generic instantiation. *) op main1(s:Stack,ist:StrictlyIntStack,i:integer,ie:IntElem,se:StrElem) = ( Push(ist,i); Push(s,ie); Push(ist,10); Push(ist,se) (* Should be ERROR because of strict inheritance. *) );