comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: Class-wide types algebra
Date: Thu, 29 Sep 2016 10:06:07 +0200
Date: 2016-09-29T10:06:07+02:00	[thread overview]
Message-ID: <nsii37$fl3$1@gioia.aioe.org> (raw)
In-Reply-To: nsh8fn$4li$1@franka.jacob-sparre.dk

On 28/09/2016 22:17, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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.

2. Where type's primitive operations are visible you cannot derive 
without resolving the conflict between hierarchies.

 From this follows that you cannot use the type in the context where 
hidden operations are visible! The type with an unresolved conflict (and 
its class-type) is invalid. Example:

    package P1 is
       type I is interface;
       procedure Foo (X : I) is abstract;

       type T1 is new T with ...;
    private
       type T1 is new T and I with ...; -- Private interface
    end P1;

    package P2 is -- We don't see private I
       type T2 is new T1 and I with null record; -- This is OK!
    end P2;

    package P1.Child_1 is -- We see private I
       type T2 is new T1 and I with null record; -- This is NOT OK
    end P1.Child_1;

    procedure P1.Child_2 is
       X : P2.T2; -- This is NOT OK, we see two instances of I in X

But of course it is also possible to allow X as we do with other cases 
when operations get hidden by each other. In that scenario X.Foo will be 
rejected as ambiguous. 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

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. 
It is not a problem, just let it be. We would also allow P1.Child_1 when 
the programmer states that I is inherited additively.

The use case for additive inheritance is multiple linked-lists:

    type Node is limited interface;
    function Next (X : Node) return Node'Class;
    ...

    type IO_Queue is
       new Node and Node with ...;

Each item participates in two lists, the list of requests and the list 
of requests from the same task (i.e. to abort them when the task completes).

> The problem here is that only (2) respects privacy at all;

Right. The user must resolve conflict when it appears. E.g.

    type IO_Queue is
       new Node as Request_List and Node as Task_List with ...;
    function Next_IO_Request ... renames Request_List.Next;
    function Next_Task_Request ... renames Task_List.Next;

I leave syntax to imagination.

>> Use-clauses, nesting, generic formals have *exactly* same issues there is
>> absolutely nothing special in inheritance.
>
> And all of those are also evil. :-)

Yes, the world is a sad place. (:-))

> They introduce significant maintenance
> problems all of the time. And they don't have the problem of requiring
> visibility on private things to resolve the conflicts. (For all of the
> above, private things stay private.)

True, and we could do same for inheritance.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

  reply	other threads:[~2016-09-29  8:06 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-12 20:26 Class-wide types algebra Dmitry A. Kazakov
2016-09-12 21:12 ` rieachus
2016-09-12 21:39   ` Dmitry A. Kazakov
2016-09-13 11:46     ` rieachus
2016-09-13 12:26       ` Dmitry A. Kazakov
2016-09-28  0:05         ` Randy Brukardt
2016-09-28  7:31           ` Dmitry A. Kazakov
2016-09-28 20:17             ` Randy Brukardt
2016-09-29  8:06               ` Dmitry A. Kazakov [this message]
2016-09-29 18:44                 ` Randy Brukardt
2016-09-29 19:55                   ` Dmitry A. Kazakov
2016-10-01  5:47                     ` Randy Brukardt
2016-10-01  8:35                       ` Dmitry A. Kazakov
2016-10-05 20:42                         ` Randy Brukardt
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox