comp.lang.ada
 help / color / mirror / Atom feed
From: Jere <jhb.chat@gmail.com>
Subject: Re: [Newbie] doubly constrained array, dumb question
Date: Tue, 27 Feb 2018 06:34:52 -0800 (PST)
Date: 2018-02-27T06:34:52-08:00	[thread overview]
Message-ID: <dc172319-53eb-41fa-ad56-6588fb440080@googlegroups.com> (raw)
In-Reply-To: <473f9b1a-6466-4745-9041-107f54062cf2@googlegroups.com>

On Monday, February 26, 2018 at 8:29:17 PM UTC-5, Mehdi Saada wrote:
> > Dmitry said:
> > 1. array's index
> > 2. array's element
> > 3. record's component
> > 4. access type's target type
> > 5. discriminant
> > 6. argument of a subroutine access type
> > 7. class-wide types (closed range of descendants T'Class (T..S))
> > 8. tagged type primitive operations (disallowing operations)
> > 9. protected and task type entries (disallowing operations)
> > 10. task type entry family
> 
> For 8: a class has any sense at all only if there's no dispatching to an inexistent method, and your forbidding some methods would do the same, raise an exception.
> So to avoid that, if you want to disallow operations (without make a dispatching call to it raises an exception), you have to cut the tagged type from its root, by hiding the fact it has a parent type, so as to disinherit the parent's method.
> If you don't want that, (I suppose) one would have to implement a per-operation basis dispatching mechanism with a list of allowed types for each methods ?
> 

Two other options:
1.  Full composition with switch statements (which is akin to that last
    sentence I quoted).
2.  The Rust inheritance model, which is a bit more complex.

I've been dorking around with Rust some and while I don't like all the
language has to offer, it's inheritance model is intriguing.  Basically,
you implement type extension purely through composition.  Normally, this
would force you to use switch statements, etc to emulate dispatching, but
in Rust, they allow you to implement interfaces (or traits as Rust calls
them).  So the design idea is anything that you actually want to dispatch
on is relegated to an interface (or multiple interfaces), and you use
classwide types of the interface to do the dispatching.  This makes for
what is practically a max 1 level deep extension tree.  Composition
allows for you to hide non dispatching operations as you see fit (I.E.
you only implement the ones you want your client to see) while the
interfaces allow you to cleanly dispatch for operations.  You are also
free to only implement the interfaces you want for each level of
inheritance.  So parent classes can implement interfaces that child
classes do not.

I'm not saying this is the end all be all method, but it is definitely
interesting to tinker with and makes you consider designs a bit
differently (much like pure composition does).

Example:
*********************************************************************

with Ada.Text_IO; use Ada.Text_IO;

procedure jdoodle is

   ------------------------------------------------------------------------
   --  This provides the interface for some dispatchable process
   --  along with a default implementation (optional).
   --
   package Dispatching is
      type Dispatchable1 is limited interface;
      procedure Do_Something(Self : Dispatchable1) is abstract;
      
      type Default_Dispatchable1 is new Dispatchable1 with null record;
      overriding procedure Do_Something(Self : Default_Dispatchable1);
      
      type Dispatchable2 is limited interface;
      procedure Do_Another(Self : Dispatchable2) is abstract;
   end Dispatching;
   
   package body Dispatching is
      procedure Do_Something(Self : Default_Dispatchable1) is
      begin
         Put_Line("Default Dispatching");
      end Do_Something;
   end Dispatching;

   ------------------------------------------------------------------------
   --  This is the base class which implements some dispatchable process
   --
   use Dispatching;
   package Base is
      type Instance is new Dispatchable1 and Dispatchable2 with private;
      overriding procedure Do_Something(Self : Instance) with Inline;
      overriding procedure Do_Another(Self : Instance);
      not overriding procedure Other_Op(Self : Instance);
   private
      type Instance is new Dispatchable1 and Dispatchable2 with record
         Parent : Default_Dispatchable1;  -- Composition
      end record;
   end Base;
   
   package body Base is
      procedure Do_Something(Self : Instance) is
      begin
         Put("Base Dispatching => ");
         Self.Parent.Do_Something;
      end Do_Something;
      
      procedure Do_Another(Self : Instance) is
      begin
         Put_Line("Another Dispatching");
      end Do_Another;
      
      procedure Other_Op(Self : Instance) is
      begin
         Put_Line("Some other op");
      end Other_Op;
   end Base;
   
   ------------------------------------------------------------------------
   --  This is a derived class which implements some dispatchable process
   --  Inheritance is done through composition.  Note that it does
   --  not proved Other_Op
   --
   package Derived is
      type Instance is new Dispatchable1 with private;
      overriding procedure Do_Something(Self : Instance) with Inline;
   private
      type Instance is new Dispatchable1 with record
         Parent : Base.Instance;  -- Composition
      end record;
   end Derived;
   
   package body Derived is
      procedure Do_Something(Self : Instance) is
      begin
         Put("Derived Dispatching => ");
         Self.Parent.Do_Something;
      end Do_Something;
   end Derived;
   
   
   ------------------------------------------------------------------------
   --  Some local variables to test with
   --
   v1 : Base.Instance;
   v2 : Derived.Instance;
   
   -----------------------------------------------------------------------
   --  Dispatching calls all handled through interface classwide types
   --
   procedure Some_Function_Call(Object : Dispatchable1'Class) is
   begin
      Object.Do_Something;
   end Some_Function_Call;
   
   procedure Some_Other_Call(Object : Dispatchable2'Class) is
   begin
      Object.Do_Another;
   end Some_Other_Call;
   
begin
   Put_Line("Starting");
   Some_Function_Call(v1);
   Some_Function_Call(v2);
   
   Some_Other_Call(v1);
   --Some_Other_Call(v2);  -- would raise a compiler error
end jdoodle;


  parent reply	other threads:[~2018-02-27 14:34 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-26 16:26 [Newbie] doubly constrained array, dumb question Mehdi Saada
2018-02-26 17:02 ` J-P. Rosen
2018-02-26 21:40   ` Dmitry A. Kazakov
2018-02-26 23:26   ` Randy Brukardt
2018-02-27  9:01     ` Simon Wright
2018-02-27 22:11       ` Randy Brukardt
2018-02-26 20:52 ` Niklas Holsti
2018-02-27  1:29 ` Mehdi Saada
2018-02-27  9:18   ` Dmitry A. Kazakov
2018-02-27 11:43     ` Mehdi Saada
2018-02-27 14:19       ` Dmitry A. Kazakov
2018-02-27 17:08     ` G. B.
2018-02-27 17:37       ` Dmitry A. Kazakov
2018-02-27 14:34   ` Jere [this message]
2018-02-27 15:13     ` Dmitry A. Kazakov
2018-02-27  7:38 ` Jacob Sparre Andersen
replies disabled

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