comp.lang.ada
 help / color / mirror / Atom feed
* How to stop inheritance in a good way?
@ 2020-01-15  8:32 reinert
  2020-01-15  9:08 ` Dmitry A. Kazakov
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: reinert @ 2020-01-15  8:32 UTC (permalink / raw)


Assume I define a tagged record (or interface) + derived types:

 type int1_t is interface;
 function A(x : int1_t) return Integer is abstract;

 type object1_t is abstract new int1_t with private;
 function A(x : object1_t) return Integer;
 function B(x : object1_t) return Integer;

 type object2_1_t is new object1_t with private;
 function C(x : object2_1_t) return Integer;

 type object2_2_t is new object1_t with private;
 function D(x : object2_2_t) return Integer;

and I want object2_2_t *not* to inherit the function B (from type object1_t).
I can make a dummy function B for object2_2_t (to override), but is it a more elegant/proper way? Or I here somehow break the concept of inheritance and enter a "dead end" ?

reinert


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15  8:32 How to stop inheritance in a good way? reinert
@ 2020-01-15  9:08 ` Dmitry A. Kazakov
  2020-01-15 20:56 ` Randy Brukardt
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Dmitry A. Kazakov @ 2020-01-15  9:08 UTC (permalink / raw)


On 2020-01-15 09:32, reinert wrote:
> Assume I define a tagged record (or interface) + derived types:
> 
>   type int1_t is interface;
>   function A(x : int1_t) return Integer is abstract;
> 
>   type object1_t is abstract new int1_t with private;
>   function A(x : object1_t) return Integer;
>   function B(x : object1_t) return Integer;
> 
>   type object2_1_t is new object1_t with private;
>   function C(x : object2_1_t) return Integer;
> 
>   type object2_2_t is new object1_t with private;
>   function D(x : object2_2_t) return Integer;
> 
> and I want object2_2_t *not* to inherit the function B (from type object1_t).
> I can make a dummy function B for object2_2_t (to override), but is it a more elegant/proper way? Or I here somehow break the concept of inheritance and enter a "dead end" ?

Inherit from object1_t privately?

    type int1_t is interface;
    function A(x : int1_t) return Integer is abstract;

    type int2_t is interface;
    function B(x : int2_t) return Integer is abstract;

    type object1_t is abstract new int1_t and int2_t with private;

    type object2_1_t is new int1_t and int2_t with private;
    overriding function A(x : object2_1_t) return Integer;
    overriding function B(x : object2_1_t) return Integer;
    function C(x : object2_1_t) return Integer;

    type object2_2_t is new int1_t with private;
    overriding function A(x : object2_2_t) return Integer;
    function D(x : object2_2_t) return Integer;

private
    type object2_1_t is new object1_t with ...;
    type object2_2_t is new object1_t with ...;

P.S. The suffix "_t" is really ugly.

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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15  8:32 How to stop inheritance in a good way? reinert
  2020-01-15  9:08 ` Dmitry A. Kazakov
@ 2020-01-15 20:56 ` Randy Brukardt
  2020-01-15 23:19 ` Jere
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Randy Brukardt @ 2020-01-15 20:56 UTC (permalink / raw)


"reinert" <reinkor@gmail.com> wrote in message 
news:755521b8-d0a8-41bd-b547-da1136e3b8e1@googlegroups.com...
...
> and I want object2_2_t *not* to inherit the function B (from type 
> object1_t).
> I can make a dummy function B for object2_2_t (to override), but is it a 
> more
>elegant/proper way? Or I here somehow break the concept of inheritance and
>enter a "dead end" ?

If you're only trying to inherit interfaces, then Dmitry's approach would 
work. If you are trying to inherit implementations as well (in this case, 
inheriting the implementation of function A for Object1_Type so you doesn't 
have to write A again for Object2_Type), then there really isn't a solution 
short of overriding with the B that raises an exception.

The reason that it has to be this way is that one can declare 
objects/parameters of type Object1_Type'Class, and a dispatching call on B 
is possible for such a type, and that call better have some body to execute. 
OOP dogma (LSP) would generally consider that broken abstraction. (I'd say 
that sometimes you have to do that to get the job done reasonably.)

                                          Randy.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15  8:32 How to stop inheritance in a good way? reinert
  2020-01-15  9:08 ` Dmitry A. Kazakov
  2020-01-15 20:56 ` Randy Brukardt
@ 2020-01-15 23:19 ` Jere
  2020-01-17  9:48   ` reinert
  2020-01-17 13:39 ` Shark8
  2020-01-17 16:56 ` AdaMagica
  4 siblings, 1 reply; 10+ messages in thread
From: Jere @ 2020-01-15 23:19 UTC (permalink / raw)


On Wednesday, January 15, 2020 at 3:32:14 AM UTC-5, reinert wrote:
> Assume I define a tagged record (or interface) + derived types:
> 
>  type int1_t is interface;
>  function A(x : int1_t) return Integer is abstract;
> 
>  type object1_t is abstract new int1_t with private;
>  function A(x : object1_t) return Integer;
>  function B(x : object1_t) return Integer;
> 
>  type object2_1_t is new object1_t with private;
>  function C(x : object2_1_t) return Integer;
> 
>  type object2_2_t is new object1_t with private;
>  function D(x : object2_2_t) return Integer;
> 
> and I want object2_2_t *not* to inherit the function B (from type object1_t).
> I can make a dummy function B for object2_2_t (to override), but is it a more elegant/proper way? Or I here somehow break the concept of inheritance and enter a "dead end" ?
> 
> reinert

It really depends on what you want object2_2_t to "be".  If it truly has a
public "is a" relationship to object1_t, then you have to accept B since
that is part of the "contract" (bad wording I know) of object1_t.  However
if you are ok with object2_2_t being a descendant of int1_t (the origin of
function A), then you can do something like the following (I added
completions to your function so I could get it all to compile):

    package Test is
        type int1_t is interface;
        function A(x : int1_t) return Integer is abstract;
        
        type object1_t is abstract new int1_t with private;
        function A(x : object1_t) return Integer is (0);
        function B(x : object1_t) return Integer is (0);
        
        type object2_1_t is new object1_t with private;
        function C(x : object2_1_t) return Integer is (0);
        
        -- Note the change here
        type object2_2_t is new int1_t with private;
        function D(x : object2_2_t) return Integer is (0); 
    private
    
        type object1_t is abstract new int1_t with null record;
    
        type object2_1_t is new object1_t with null record;

        -- See how the inheritance is listed differently
        type object2_2_t is new object1_t with null record;
    
    end Test;


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15 23:19 ` Jere
@ 2020-01-17  9:48   ` reinert
  2020-01-17 21:17     ` Optikos
  0 siblings, 1 reply; 10+ messages in thread
From: reinert @ 2020-01-17  9:48 UTC (permalink / raw)


Seems like I end up in a mess if I try to avoid such inheritance :-)

Maybe better to try to stick properly with the OOP dogmas and shape up the concepts.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15  8:32 How to stop inheritance in a good way? reinert
                   ` (2 preceding siblings ...)
  2020-01-15 23:19 ` Jere
@ 2020-01-17 13:39 ` Shark8
  2020-01-20  4:32   ` ric.wai88
  2020-01-17 16:56 ` AdaMagica
  4 siblings, 1 reply; 10+ messages in thread
From: Shark8 @ 2020-01-17 13:39 UTC (permalink / raw)


On Wednesday, January 15, 2020 at 1:32:14 AM UTC-7, reinert wrote:
> 
> and I want object2_2_t *not* to inherit the function B (from type object1_t).
Well, there's two ways that you could do this:
(1) If you don't need to pass the object to Object1_T'Class parameters or do inline view-conversions then simply make Object2_T a private type, copying over the interface you want to expose, with the inheritance in the full-view.
(2) If you need to ensure that there is direct/visible inheritance, you could use generics and the "is null" default on functions to control behavior.

GENERIC
  Type XX(<>) is abstract new Object2_T with private; -- You could use Int1_T.
  with Function A_Implementation(X : XX) return Integer is null;
  with Function B_Implementation(X : XX) return Integer is null;
  --...
Package Selective is
  Type Child is new XX with null record;

  Overriding Function A( Object : Child ) return Integer;
  --...
Private
  Function A( Object : Child ) return Integer is
   ( A_Implementation(XX(Object)) );
  --...
End Selective;


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-15  8:32 How to stop inheritance in a good way? reinert
                   ` (3 preceding siblings ...)
  2020-01-17 13:39 ` Shark8
@ 2020-01-17 16:56 ` AdaMagica
  2020-01-17 23:51   ` Jeffrey R. Carter
  4 siblings, 1 reply; 10+ messages in thread
From: AdaMagica @ 2020-01-17 16:56 UTC (permalink / raw)


Thére were many solutions presented, none really convincing. If you have full control over the inheritance hierarchy, you can design it as you want it to be.

On the other hand, if the hierarchy is given, there is no good solution IMHO.

However, I have problems to see how a derived type might have less operations than the parent. But you can always override with a null procedure or raise an exception, as has been proposed.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-17  9:48   ` reinert
@ 2020-01-17 21:17     ` Optikos
  0 siblings, 0 replies; 10+ messages in thread
From: Optikos @ 2020-01-17 21:17 UTC (permalink / raw)


On Friday, January 17, 2020 at 3:48:02 AM UTC-6, reinert wrote:
> Seems like I end up in a mess if I try to avoid such inheritance :-)
> 
> Maybe better to try to stick properly with the OOP dogmas and shape up the concepts.

Perhaps you should describe •why• you want to elide function B from object2_2_t so decisively & firmly.  Most commenters on this posting are perplexed by why you would want polymorphism via object1_t'Class that is permitted to invoke B in the object2_1_t situation but is prohibited at compile-time* from invoking B in the object2_2_t situation, such as a heterogenous mixture of instances of object2_1_t and of object2_2_t.  You should describe the intended usage in package bodies more (and let the package specifications be rather unrestricted degree[s] of freedom to match your intended usage).  Indeed, doing so might lead you yourself to the solution as you refine your thinking; we'd be interested in seeing your solution to your rejiggered problem-statement even if you solve it yourself.

* which seems to be reinert's stated desire, not throwing an exception at run-time

Because we cannot completely see the intended usage in the package bodies and what precisely needs to be prohibited at compile-time and where, we cannot really present a detailed solution, nor discuss intermediate to advanced topics such as invariance, covariance, contravariance, and bivariance (not all of which are supported by Ada directly or by emulation).

Conversely, I have seen such defeat-the-isa-contract questions arise perennially in multiple OO programming languages for decades, so this is in the ballpark of some question that deserves a no-no don't do that do this instead style of answer.  Usually the answer to a similar question touches on 1 or more of:  covariance, contravariance, declaration-site variance annotations, and/or usage-site variance annotations (or in the case of C++, dangerous techniques and/or various forms of type casting and/or slicing aberrant behavior).

One solution could be that invoking object2_2_t's B is not a compile-time error (and not a raised exception either) but rather simply a do-nothing no-op in the object2_2_t case when invoked polymorphically via object1_t'Class.  This would be an application of the no-harm-no-foul principle.  But we cannot see whether this elision at run-time fits with reinert's intended usage throughout package bodies.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-17 16:56 ` AdaMagica
@ 2020-01-17 23:51   ` Jeffrey R. Carter
  0 siblings, 0 replies; 10+ messages in thread
From: Jeffrey R. Carter @ 2020-01-17 23:51 UTC (permalink / raw)


On 1/17/20 5:56 PM, AdaMagica wrote:
> Thére were many solutions presented, none really convincing.
Probably the OP's problem is one for which programming by type extension is not 
a good approach. Trying to distort programming by type extension to fit the 
problem will never work. One should find another approach that is better suited 
to the problem.

-- 
Jeff Carter
"I'm particularly glad that these lovely children were
here today to hear that speech. Not only was it authentic
frontier gibberish, it expressed a courage little seen
in this day and age."
Blazing Saddles
88


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: How to stop inheritance in a good way?
  2020-01-17 13:39 ` Shark8
@ 2020-01-20  4:32   ` ric.wai88
  0 siblings, 0 replies; 10+ messages in thread
From: ric.wai88 @ 2020-01-20  4:32 UTC (permalink / raw)


On Friday, January 17, 2020 at 8:39:59 AM UTC-5, Shark8 wrote:
> On Wednesday, January 15, 2020 at 1:32:14 AM UTC-7, reinert wrote:
> > 
> > and I want object2_2_t *not* to inherit the function B (from type object1_t).
> Well, there's two ways that you could do this:
> (1) If you don't need to pass the object to Object1_T'Class parameters or do inline view-conversions then simply make Object2_T a private type, copying over the interface you want to expose, with the inheritance in the full-view.
> (2) If you need to ensure that there is direct/visible inheritance, you could use generics and the "is null" default on functions to control behavior.
> 
> GENERIC
>   Type XX(<>) is abstract new Object2_T with private; -- You could use Int1_T.
>   with Function A_Implementation(X : XX) return Integer is null;
>   with Function B_Implementation(X : XX) return Integer is null;
>   --...
> Package Selective is
>   Type Child is new XX with null record;
> 
>   Overriding Function A( Object : Child ) return Integer;
>   --...
> Private
>   Function A( Object : Child ) return Integer is
>    ( A_Implementation(XX(Object)) );
>   --...
> End Selective;

Unfortunately you can't use "is null" on functions, only procedures..


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-01-20  4:32 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-15  8:32 How to stop inheritance in a good way? reinert
2020-01-15  9:08 ` Dmitry A. Kazakov
2020-01-15 20:56 ` Randy Brukardt
2020-01-15 23:19 ` Jere
2020-01-17  9:48   ` reinert
2020-01-17 21:17     ` Optikos
2020-01-17 13:39 ` Shark8
2020-01-20  4:32   ` ric.wai88
2020-01-17 16:56 ` AdaMagica
2020-01-17 23:51   ` Jeffrey R. Carter

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