(* * This file contains some initial investigations on what nice things can * happen with the rule T = {T}, for any type T. * * SUPER FLASH: where-clause instantiation must DISABLE subtype polymorphism, * since it fundamentally alters the subtype. Consider the example below, * where IntStack < Stack. In this case, an Instack no longer shares a rep * with Stack, since we've changed it with the where clause. Looking at what * happens to a selector, with and without where clause, can help clarify * things. * * WITH WHERE: obj Stack = es:Elem*; obj IntStack < Stack where: Elem = IntElem end; op Top(ist:IntStack)->IntElem = ist.e[1] * * Here the type of ist.es[1] is IntElem, due to the generic instantiation. * I.e., the type of ist.es is now IntElem*, again, due to the generic * instantiation. Further, the type of ist.es CANNOT be interpreted as Elem* * anymore (as it is in the parent Stack class) since this would allow Elem's * to mascarade as IntElem's, via a violation of subtype poly. I.e., since * IntElem < Elem, we cannot bind Elem's to vars of type IntElem, and with * generic where-clause instantiation, ist.es is a list of such vars. Hence, * the where-clause instantiation has led to a severing of the subclass * relationship between Stack and IntStack, as far as any subsequent type * checking is concerned. Bitchin. * * WITHOUT WHERE: obj Stack = es:Elem*; obj IntStack < Stack op Top(ist:IntStack)->IntElem = ist.es[1]?Stack; op Push(IntStack,IntElem)->IntStack; (* This op should be automatically def'd by generic instantiation. *) op Push(StrStack,StrElem)->IntStack; (* Ibid re. auto def. *) op Pop(Stack)->Elem; op Pop(ist:IntStack)->IntElem = (* Ibid. *) ist.e[1]; (* (Imple obviously not auto) *) op Pop(StrStack)->StrElem; (* Ibid. *) op main(s:Stack,ist:IntStack,i:integer,ie:IntElem,se:StrElem) = ( Push(ist,i); (* Works by T = {T} rule. *) Push(ist,10); (* Ibid. *) Push(s,ie); (* Works, since IntElem < Elem *) Push(s, i); (* ERROR, since int !< Elem, and T={T} cant help *) Push(ist,se) (* ERROR, per new superflash rule. *) (* Same as next line before constructor ops work *) -- Push(ist,StrElem("abc"))(* Potentially problematic; see discussion below.*) ); (* * 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. *) );