From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Class-wide types algebra Date: Thu, 29 Sep 2016 21:55:27 +0200 Organization: Aioe.org NNTP Server Message-ID: References: <2837d915-12c8-4c23-8907-1d146d1abae7@googlegroups.com> NNTP-Posting-Host: 1YuCPr00zqg9zND3Lb27jw.user.gioia.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news.eternal-september.org comp.lang.ada:31948 Date: 2016-09-29T21:55:27+02:00 List-Id: On 2016-09-29 20:44, Randy Brukardt wrote: > "Dmitry A. Kazakov" wrote in message > news:nsii37$fl3$1@gioia.aioe.org... >> On 28/09/2016 22:17, Randy Brukardt wrote: >>> "Dmitry A. Kazakov" wrote in message >>> news:nsfrn6$ab7$1@gioia.aioe.org... >>>> On 28/09/2016 02:05, Randy Brukardt wrote: >>> ... >>>>> The problem with all forms of MI is diamond inheritance, which get much >>>>> worse in Ada because of our strict privacy rules. >>>> >>>> There is no any problems with diamond inheritance and visibility. >>> >>> Certainly are. If one has a hidden interface with hidden overridden >>> operations, and a later extension tries to add the same interface with >>> different overridden operations, one of two things has to happen, both >>> bad: >>> (1) The interfaces are the same, so the hidden operations completely >>> disappear. (The new extension cannot know that they ever existed, so they >>> cannot be called from it.) Since the parent operation presumably depends >>> on >>> those operations, trouble is certain to ensue. (When the operations >>> aren't >>> overridden, then they magically become visible, which is also a problem.) >>> (2) The interfaces are different, so one has problems in dispatching >>> calls >>> of figuring out which one to call. That way leads to madness. >> >> It is clearly #2. What you cannot see does not exist, the old good >> solipsism. Ada sometimes violates this principle, always for worse. >> >> There is no problem with dispatching calls so long visibility is >> respected: >> >> 1. Where type's primitive operations are not visible you cannot dispatch >> to them. > > ??? You can always convert an object of the type to the class-wide interface > (which is legal in this scenario, even if not in the private part), and make > a dispatching call. (That's the case that's a problem.). No, you cannot, you don't see if the type inherits the interface, so you cannot convert to its class. > Which overriding operation do you get? None, that is illegal, the type does not implement the interface inherited privately. There is no overriding, there is no class in any public scope. > If it depends on visibility, you have madness (what > happens depends on where it is written - yuck). Nope, that is what visibility all about. You don't see inheritance, you don't have it. Period. >> 2. Where type's primitive operations are visible you cannot derive without >> resolving the conflict between hierarchies. > > Sure. But that doesn't fix anything. > >> From this follows that you cannot use the type in the context where hidden >> operations are visible! > > No problem, but the problem is with the type with two copies of the > interface. How does the conversion to I'Class work (that conversion is > implicit in calls to class-wide subprograms)? It will work just fine. In any context only one inheritance is visible or else conversion is ambiguous and thus illegal (unless resolved). > How does it chose which interface to use? The one visible in this context. There is no unresolved conflicts, in any given context it is unambiguous. > ... >> Yes, when X were passed as a class-wide of another root type dispatching >> to Foo would take the hierarchy of I that this root type uses. It is all >> consistent. >> >> Y : T1'Class := ...; -- This OK, we see only private I >> begin >> Y.Foo; -- This dispatches on I inherited in P1, WYSIWYG >> >> procedure Public is >> X : P2.T2; -- This is OK, we respect privateness >> begin >> X.Foo; -- This dispatches on I inherited in P2 > > Actually, this is madness. Nothing "consistent" about it. Why? Because if > you move the call to some outside routine (say some other dispatching > operation), the meaning changes. Which means that one can't use > abstractions. Very, very bad. Nothing mad here. You change the type of X that changes the operation. Why X / Y must mean same for Integer X, Y and Float X, Y? How Foo is different from "/"? >> The important point is that inheritance can be additive as in the case >> when I is inherited once privately and once publicly. If succeeds then the >> outcome is *two* hierarchies. >> >> You cannot forbid that altogether, which is why you see it as a problem. > > Well, actually we do: we forbid the private inheritance completely, because > there is no consistent and sensible set of rules for what it would mean. By violating privacy, by introducing ugly artifacts, by piling up nonsense rules... >> It is not a problem, just let it be. > > The implementation of two copies of the same interface would break any of > the existing algorithms for implementing interfaces. (I have absolutely no > idea how that could be accomplished; it would depend on how the dispatching > rules were eventually worked out.) It breaks nothing. You get two hierarchies independent on each other. You already can do just this with ease: generic package P is type I is interface; procedure Foo (X : I) is abstract; end P; package P1 is new P; package P2 is new P; type T is new P1.I and P2.I with null record; overriding procedure Foo (X : T); How is it different from: type T is new I and I with null record; Or this: generic type S is (<>); package P is type I is interface; procedure Foo (X : I; Y : S) is abstract; end P; type T is new P1.I and P2.I with null record; overriding procedure Foo (X : T; Y : Integer); overriding procedure Foo (X : T; Y : Boolean); You cannot prevent things like this once you introduced MI. There is only one way to do MI right and it is not the one Ada presently goes. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de