Path: news.daimi.aau.dk!news.uni-c.dk!sunic!ugle.unit.no!nac.no!eunet.no!nuug!EU.net!uunet!news.claremont.edu!nntp-server.caltech.edu!nntp-server.caltech.edu!derway From: derway@ndc.com (D. Erway) Newsgroups: comp.lang.beta,comp.lang.eiffel,comp.object Subject: Re: On why BETA does not have multiple inheritance Date: 15 Sep 1994 19:36:47 GMT Organization: NDC Systems - Monrovia, CA Lines: 130 Message-ID: References: <358nrv$bpf@engnews2.Eng.Sun.COM> NNTP-Posting-Host: alumni.caltech.edu To: olm@Eng.Sun.COM (Ole Lehrmann Madsen) In-reply-to: olm@Eng.Sun.COM's message of 15 Sep 1994 05:59:27 GMT Xref: news.daimi.aau.dk comp.lang.beta:50 comp.lang.eiffel:6193 comp.object:19317 Hi. Thankyou for contributing such clarity to the discussion! Your message 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. >>>>> "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. 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. 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)? 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? 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? Thanks, Don Erway