Path: news.daimi.aau.dk!news.uni-c.dk!sunic!pipex!howland.reston.ans.net!agate!ames!lll-winken.llnl.gov!koriel!news2me.EBay.Sun.COM!engnews2.Eng.Sun.COM!olm From: olm@Eng.Sun.COM (Ole Lehrmann Madsen) Newsgroups: comp.lang.beta,comp.lang.eiffel,comp.object Subject: Re: On why BETA does not have multiple inheritance Date: 19 Sep 1994 06:28:51 GMT Organization: Sun Microsystems Inc., Mountain View, CA Lines: 196 Message-ID: <35jb33$3q1@engnews2.Eng.Sun.COM> References: <358nrv$bpf@engnews2.Eng.Sun.COM> NNTP-Posting-Host: det.eng.sun.com X-Newsreader: NN version 6.5.0 #21 (NOV) Xref: news.daimi.aau.dk comp.lang.beta:72 comp.lang.eiffel:6210 comp.object:19397 derway@ndc.com (D. Erway) writes: >Hi. Thankyou for contributing such clarity to the discussion! Your message Thanks! >helped me see some things more, and made Eiffel's approach to MI seem even >more sensible. Have you looked at Eiffel? What do you see as wrong with its >approach to MI? I am truly asking here, not trying, (too much :) to >proselytize. Yes, I have looked at Eiffel, and C++, CLOS, and a number of other proposals. These languages have all made a number of useful contributions, but I think that their handling of MI is still rather complex. In cases with overlapping superclasses where some features are inherited one time and others more than one time, I find it hard to understand the Eiffel rules for rename/redefine. In general I think that for conceptual modelling, the features of a common superclass should be inherited eaxcly once. Please note, that I am not trying to flame here. I know that many people like the Eiffel, C++ and/or CLOS way of doing MI, and this is good. The intent of my original posting was to describe why there is no MI in BETA. It is ok that you try to proselytize me, but I certainly think that you should try BETA:-) >>>>>> "Ole" == Ole Lehrmann Madsen writes: > Ole> Finally, we have not felt an strong need to support MI in the > Ole> traditional sense, since BETA has other means for handling some of the > Ole> most common MI cases: > Ole> In BETA you may inherit from part-objects and at the same time bind > Ole> virtuals in the part-object > Ole> A: (# f:< ... #) B: (# g:< ... #) > Ole> C: (# ... X: @ A(# f::< (# ... #) ... #); Y: @ B(# g::< (# ... #) > Ole> ... #); ... #); > Ole> X and Y are singular part-objects. The virtual bindings of f and g may > Ole> due to BETA's block structure refer to variables in the enclosing > Ole> C-object. > Ole> Consider > Ole> W: ^ C > Ole> The functions f and g may be invoked as > Ole> W.X.f W.Y.g > Ole> The difference from MI is that you have to qualify using X and Y. Some > Ole> think this is inconvenient. Others thinks it is an advantage since you > Ole> are explicit about name-conflicts between A and B. >Another difference is that the redefined part-objects are not available as >classes in their own right, to be inherited from individually by yet other >classes. You may define local classes as in C: (# ... CX: A(# f::< (# ... #); X: @CX; CY: B(# ... #); Y: @CY #) You may now inherit from CX and CY, either in subclasses of C CC: C(# ... CXX: CX(# ... #); CYY: CY(# ... #); ... #) or remotely myC: @C; CXX: myC.CX(# ... #) > Ole> If you prefer writing W.f and W.g, you may define f and g functions in C > Ole> and let the forardthe call to X.f and Y.g repectively. >Yes, but W.f will not be polymorphically identical to W.X.f. It may call it, >but is a clear chance for error to creep in. I agree. > Ole> Consider > Ole> V: ^A > Ole> Then > Ole> W.X[] -> V[] > Ole> is possible, and an invocation V.f call the virtual binding of f the > Ole> object X, and thereby possibly accesing/changing the state of C. >Yes, but in Eiffel MI each object can be passed or assigned to a reference to >any parent, without having to call out the part that is meant. This seems >very much simpler. Isn't this even true in C++ (as long as value semantics >are avoided)? You are right. The examples are NOT to show that BETA has MI, but to show how you can deal with a number of MI cases in BETA as it is. > Ole> As a final example, consider the following well-know MI case: > Ole> Window > Ole> / \ > Ole> WindowWitBorder WindowWithTitle > Ole> \ / > Ole> WindowWithTitleAndBorder > Ole> In BETA this may be handled using block-structure > Ole> (the exsample is due to Kasper \sterby - he has an article about this > Ole> and I am sure he can supply the exact reference - kasper@iesd.auc.dk) > Ole> Window: > Ole> (# ... > Ole> Border: (# ... #); > Ole> Title: (# ... #); > Ole> #); > Ole> W1: @Window(# B: @Border; T: @Title #) > Ole> W2: @Window(# T1,T2: @Title #) > Ole> Here W1 has a border and a title, whereas W2 has no border and two > Ole> titles. >This is really neat, but if all you have is a borderless, titleless window, in >a library, how can you accomplish this? I am not sure what the question is here? The Window class in the library has local classes defining Border's and Title's. The instation (initialization) of W1 and W2 will have to setup the proper relations between the Window objects and its part objects (Tile-instances and Border-instances) >This structure: > Ole> Window > Ole> / \ > Ole> WindowWitBorder WindowWithTitle > Ole> \ / > Ole> WindowWithTitleAndBorder >and the issues it raises reminds exactly of merging two divergent branches of >a source code file. Window is the ancestor version, WWB is one modification, >and WWT is an other. In merging files, (for instance with the gnu emacs emerge >facility), the assumptions are: > 1) Whatever is the same in all three versions, (ancestor & 2 > versions), can be left the same in the merged version. > 2) Where one version is the same as the ancestor, and the other is > different, we assume the the changed one takes priority, (i.e. changes > are intentional). > 3) Where both versions differ from the ancestor, there is conflict, > that must be manually resolved. >In practice, using these assumptions works 100% of the time for correctly >merging file versions. Further, case 3, where there are conflicting changes >occurs VERY rarely. (I have merged 100K lines of code that I have worked on >for 6 months, with the main versions that were being massively transformed >full time by 3 other programmers, and the merge was done in one morning!) >It seems to me that these are the same assumptions made in the MI model of >Eiffel, and that they will hold just as well - conflict will be very rare, and >when it does occur, Eiffel offers simple mechanisms to resolve it. >Since so many smart people are saying that MI is too complicated, I assume I >must be missing something. Can you fill me in? If your experience with MI in Eiffel is that it is simple and works fine, then this is good! As I said earlier I am not trying to argue against other languages, but just to explain why MI is not in BETA. I have seen a lot of examples of code where heavy use of MI made it very difficult to figure out what is going on. I think that language constructs should have a simple semantics. Finally, my experience is that real 'MI' situations occur very rarely in practice and for BETA it has not been considered worth the effort to include it. ---olm > Thanks, > Don Erway