comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: OO problem: Performing actions on messages (very long, sorry)
Date: Wed, 5 Jan 2005 14:23:50 +0100
Date: 2005-01-05T14:23:50+01:00	[thread overview]
Message-ID: <1odpvi9429wrb.r854wtzbr1qm$.dlg@40tude.net> (raw)
In-Reply-To: 1104926478.797780.7830@c13g2000cwb.googlegroups.com

On 5 Jan 2005 04:01:18 -0800, per wrote:

>>> I see! So you're saying that I need one instantiation for each
>>> *Put-procedure* and message (instead of one for each *type* and
>>> message)? Hm, that's a lot of instances in my system...
> 
>>Right, generics are said to be statically polymorphic, to underline that
>>there is a better, true polymorphism. (:-))
> 
> OK, I agree true polymorphism is preferable.
> 
> Do you dare to say that ALL generics *could* be implemented with true
> polymorphism?
> 
> If so, do you dare to say that ALL generics *should* be implemented
> with true polymorphism? (Just curious.)

Well, yes, in my view generics should be depreciated. And future evolution
of Ada should pursue the goal of removing any need in generics where
possible. Though beware, most of Ada people disagree with me!

>>I would try to get rid of generics. The main problem why generics appear in
>>your case is that you have parallel type hierarchies. No language, I know
>>of, can gracefully handle that. Remove parallelism and things will become
>>much simpler. For example,
>>
>>1. If the number of different argument types is limited, you could make all
>>possible variants of Put primitive operations of Message:
>>
>>type Message is abstract tagged ...
>>procedure Put (M : in out Message; Value : Ihteger);
>>procedure Put (M : in out Message; Value : Float);
> 
> But... What if the descendant to Message has many fields of the same
> type (as definitely is the case for me):
> 
> type Message.M1 is new Message with
> record
> A : Integer;
> B : Integer;
> end;
> 
> What field would be assigned by
> 
> procedure Put (M : in out Message.M1; Value : Integer);

It is a suspicious design. What is the difference between fields A and B?
Only names? If so then there should be an integer array instead. So you go
as follows:

type Index is new Positive;
type Integer_List is array (Index range <>) of Integer;
procedure Put (M : in out Message; Value : Integer; Position : Index);

type Message.M1 (List_Size : Natural) is new Message with record
   List : Integer_List (1..Size);
end record;

If there is some semantic difference between A and B, then from design
point of view it has to be mapped into types. So you will have:

type Port_Number is new Integer range 1..10_000;
type Annual_Income is new Integer range 0..100_000_000;

procedure Put (M : in out Message; Value : Port_Number);
procedure Put (M : in out Message; Value : Annual_Income);

Ada encorages and assists design in terms the application domain, rather
than focused on implementation details.

>>2. Another axis is that action have to contain message of potentially
>>unknown type. You already handled that by declaring a common ancestor for
>>all messages. So you could aggregate Message'Class into Action instead of
>>doing so for a specific Message. The latter requires generics, the former
>>does not. Though you cannot do it directly: (*)
>>
>>type Override (Argument : access Message'Class) is new Action with record
>>  Argument : Message'Class; -- This is not Ada!!
>>end record;
>>
>>But you can use mix-in:
>>
>>type Override (Argument : access Message'Class) is new Action ...;
>>
>>Here each instance of Override has a "pointer" (access discriminant) to its
>>message. This approach might become difficult when the scope of action is
>>not nested in one of the message. Also it would require Action to be a
>>limited type. So, alternatively you can make reference counting for
>>messages and have handles (smart pointers) to them in actions. There are
>>ready-to use implementations of smart pointers in Ada. With this approach
>>you can pass a handle to message instead of the message object. For example
>>Override would just assign one handle to another without any copying. In
>>some cases it might become much more efficient than parameter marshaling,
>>which is what I suppose you are trying to do. The price to pay is that you
>>will need to handle aliasing, concurrent changes of a message etc.
> 
> OK, some of this is a bit beyond my Ada knowledge I'm afraid (remember
> I'm still an Ada newbie ;), but I kind of get your point. Lots of new
> stuff for me so next questions may be stupid:
> 
> Would this approach cope with that the actions are not connected to a
> certain message *instance* until the point the action should execute?
> The action at most only "knows" what *type* (or should I say class) of
> message it should execute upon, and the message instance existsonly
> close (in time) to the moment the action executes and not under the
> actions entire life-time.

Handles decouple object scopes. It has advantages and disadvantages. The
rule of thumb is that if you can do object scopes statically determinable,
do it. The decision depends on your requirements. If action objects are
tightly bound to defininte message objects then I would use mix-in instead
handles.

> When you say "For example Override would just assign one handle to
> another without any copying" it seems that you mean a handle to an
> entire message? If so, that's not what an override action is supposed
> to. Only a single field *inside* the message should be overridden. Or
> have I misunderstood you completely?

OK, I see. But then the question to answer what purpose serves message
apart from being just a container for unrelated data? The difficulties of
the design come from that missing pupose. If there is nothing in common
then nothing can be programmed for that nothing. (:-))

> I would like to avoid lots of copying since the system is a real-time
> simulator so  using handles is tempting. In practice I think most
> parameters will be "small" though (Integer, Float, bitfields etc) so
> it's not a big deal.

Hmm, what about this mix-in:

package Interfaces is
   type Message is abstract tagged ...
   type Action is abstract tagged limited ...;
   procedure Execute (This : in out Action) is abstract;
end Interfaces;

package M1_Thinds is
   type M1 is new Message with record -- Message M1
      A : Integer;
      B : Float;
   end record;

   type M1_Action (Data : access M1) is -- Abstract actions on M1
      abstract new Action with null record;

   type Override_A is new M1_Action with record
      A : Integer;
   end record;
   procedure Execute (This : in out Override_A);

   type Override_B is new M1_Action with record
      B : Float;
   end record;
   procedure Execute (This : in out Override_B);
   ...

package body M1_Things
   procedure Execute (This : in out Override_A) is
   begin
      This.Data.A := This.A;
   end Execute;

   procedure Execute (This : in out Override_B) is
   begin
      This.Data.B := This.B;
   end Execute;

Here all actions on some type of messages have a "pointer" to the
corresponding message object. The scope of an action should be nested in
the scope of the message.

Here in fact action is a pointer to message extended with some additional
data. When scopes get different, then action could be a handle to message.
Messages will be collected using reference counting.

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



  reply	other threads:[~2005-01-05 13:23 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-12-22 13:49 OO problem: Performing actions on messages (very long, sorry) per
2004-12-22 15:17 ` Dmitry A. Kazakov
2004-12-22 16:28 ` Martin Krischik
2004-12-22 17:42   ` per
2004-12-22 18:16     ` Martin Krischik
2004-12-22 19:54     ` Dmitry A. Kazakov
2005-01-03 12:37       ` per
2005-01-03 14:14         ` Dmitry A. Kazakov
2005-01-04 12:05           ` per
2005-01-04 13:30             ` Dmitry A. Kazakov
2005-01-04 15:21               ` per
2005-01-04 17:47                 ` Dmitry A. Kazakov
2005-01-05 12:01                   ` per
2005-01-05 13:23                     ` Dmitry A. Kazakov [this message]
2005-01-05 15:59                       ` per
2005-01-05 20:44                         ` Dmitry A. Kazakov
2005-01-10  8:42                           ` per
2005-01-10 14:22                             ` Dmitry A. Kazakov
2005-01-10 16:24                               ` per
2005-01-10 19:09                                 ` Dmitry A. Kazakov
2005-01-11  9:06                                   ` per
2004-12-22 17:46   ` per
2004-12-22 18:02     ` Martin Krischik
2005-01-03 10:05       ` per
2004-12-22 18:35     ` u_int32_t
2004-12-22 18:38       ` u_int32_t
2004-12-24 18:52 ` Nick Roberts
2005-01-03 16:59   ` per
2005-01-10 12:10   ` per
2005-01-10 13:49     ` Marius Amado Alves
2005-01-10 21:54 ` Simon Wright
replies disabled

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