Re: [q-lang-users] Subtypes and Interfaces
Brought to you by:
agraef
From: Albert G. <Dr....@t-...> - 2007-06-09 10:44:15
|
Rob Hubbard wrote: > This is probably not a good time to pose questions unrelated to the > imminent 7.7 release. Sorry. No problem, now that only the final touches are left to do, I do have time to respond to email again. ;-) > Suppose I have (parametrised) types > > public type T1 = private const nil F; > public type T2 : T1; // a variant with special meaning The above declaration is already where the problem lies: T2 doesn't have any constructors and therefore the type is empty! In most case, the constructors should be part of the subtype's declaration, not the supertype's. Like so: public type T1; public type T2 : T1 = private const t2_const X; If you do it like this, then constructor terms of the form t2_const X match *both* T2 *and* T1: t1_foo Y:T1 = ...; // will work with both T2 and other T1 objects t2_foo Y:T2 = ...; // will only work with T2 objects In Q subtyping just means that an object of a given type T matches the type guard ':T' itself as well as the guards of all its supertypes. In this sense, the supertype actually "inherits" the constructors of all its *subtypes*, not the other way round. I know that this is a bit confusing, because in traditional OOP an object is actually a kind of record a.k.a. structure which is inherited by the subtype in addition to the supertype's interface operations. But if you think about it then you'll realize that Q's way of doing this actually makes sense, since the set of instances of a supertype must contain all the sets of instances of its subtypes. In fact, Q's OOP model is considerable more general than that of most traditional OOP languages (with single inheritance). In those languages, a subtype of a given type T1 can only take the form of a product type T2 = T1 x T2'. In Q, *any* type can be a subtype of another, regardless of the internal representation. This works because subtypes never inherit the internal representations of their supertypes. Of course this also raises the "abstraction barrier". There are cases in which you would like to have a supertype have its own concrete representation and also share this representation with the subtype. It's possible to achieve this by just making the "guts" of the T1 object a part of the T2 object: public type T1 = private const t1_const X; public type T2 : T1 = private const t2_const X Y; This works pretty much like the product type approach of traditional OOP. You can then project a T2 object onto T1 simply as follows: upcast (t2_const X _) = t1_const X; But note that then you break the abstraction barrier, i.e., whenever you change the internal representation of T1 you'll have to look after T2 as well (that's one shortcoming of traditional OOP: changes to the internal representation of a type T ripple through the entire subtype hierachy rooted at T). I hope that this made things a bit clearer. Well, I realize that this should probably be in the manual. Oh well, another nice section for my book. ;-) Cheers, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |