comp.lang.ada
 help / color / mirror / Atom feed
From: "per" <commander@death-star.com>
Subject: OO problem: Performing actions on messages (very long, sorry)
Date: 22 Dec 2004 05:49:54 -0800
Date: 2004-12-22T05:49:54-08:00	[thread overview]
Message-ID: <1103723394.299024.314670@c13g2000cwb.googlegroups.com> (raw)

Hi all,

I'm new to Ada (but not to OO). I'm having trouble designing a system,
or at least a key part of it. (I have a few alternative non-tested
solutions but I don't get why this doesn't work.) And I'd like to do it
"by the book" in nice OO Ada coding style.

The system handles "general" messages and "general" actions that may be
performed on the messages. I'm trying to utilize inheritage, polymorphy
and generics to solve this.

You may now:
1. Continue and read the entire post
2. Skip to Code and Questions
3. Skip to Questions

Description
-----------

There's an abstract parent-class, Action, and non-abstract children,
Action.Override, Action.Error, Action.Record etc.

Each action child shall be able to "do something" with a message in the
virtual (is that the Ada term?) procedure Execute.

The action Action.Override serves as an example in this post. This
action shall override a field in a message.

All actions are created and then enqueued in certain action queues in a
preparation phase and then executed (real-time) in the execution phase.
The messages are both created and transported through the system in the
execution phase.

In order to store the value to override with, and where to put it when
performing the override, the Action.Override stores an override
argument (like a Float for instance) and an access to the proper
Put-procedure (like Put_A(M : in out Message.M1.Instance; A : Float))
for a certain message class instance (the specific message the action
shall operate upon). The Put procedure takes as arguments the message
instance and a value to put. The procedure name defines what message
field to put the value into, such as Put_A for field A.

The type of the field to override and the type of the message are
generic parameters in the Action.Override package/class, so there's one
instantiation of Action.Override for each message type and override
type:

package M1_Float_Override_Action is new Action.Override
(ArgumentType => Float,
MessageType  => Message.M1.Instance);

There's another abstract parent-class, Message, and non-abstract child
classes Message.M1, Message.M2 etc.

Each child message has its own set of, non-virtual, Put procedures that
writes the contents of the message. The message contents is a record
with arbitrary width, depth and types.

There will also be a nice general mechanism that basically gets any
type of message, applies any actions enqueued for it and then puts the
message away. It feels like this should be possible with Ada mechanisms
such as inheritage, polymorphy and generics but, I kind of doubt it
now...

Code
----

--Abstract base class Message:

package Message is
type Instance is abstract tagged private;
type Reference is access all Instance;
type Class_Reference is access all Instance'Class;
...
private
type Instance is abstract tagged
record
...
end record;
end Message;
package body Message is
...
end Message;


--Concrete child class Message.M1:

package Message.M1 is
type Instance is new Message.Instance with private;
type Reference is access all Instance;
type Class_Reference is access all Instance'Class;
...
procedure Put_A(Self  : in out Instance;
New_A : in     Float);
procedure Put_B(...
...
private
type Instance is new Message.Instance with
record
A : Float;
B : Integer;
...
end record;
end Message.M1;
package body Message.M1 is
...
procedure Put_A(Self  : in out Instance;
New_A : in     Float) is
begin
Self.A := New_A;
end;
...
end Message.M1;


--Abstract base class Action:

package Action is
type Instance is abstract tagged private;
type Reference is access all Instance;
type Class_Reference is access all Instance'Class;
...
procedure Execute(Self : in out Instance;
M    : in     Message.Class_Reference) is abstract;
...
private
type Instance is abstract tagged
record
...
end record;
end Action;
package body Action is
...
end Action;


--Concrete generic child class Action.Override:

generic
type ArgumentType is private;
type MessageType is private;
package Action.Override is
type Instance is new Action.Instance with private;
type Reference is access all Instance;
type Class_Reference is access all Instance'Class;
...
type OverrideMethodRefType is access procedure(M : in out
MessageType;
A : in
ArgumentType);
procedure Initialize
(Self      : in out Instance;
Tick      : in     Integer;
Arg       : in     ArgumentType;
MethodRef : in     OverrideMethodRefType);

procedure Execute(Self : in out Instance;
M    : in     Message.Class_Reference);
...
private
type Instance is new Action.Instance with
record
Argument          : ArgumentType;
OverrideMethodRef : OverrideMethodRefType;
end record;
end Action.Override;
package body Action.override is
...
procedure Initialize
(Self      : in out Instance;
Tick      : in     Integer;
Arg       : in     ArgumentType;
MethodRef : in     OverrideMethodRefType) is

begin
Initialize(Action.Instance(Self), Tick);
Self.Argument          := Arg;
Self.OverrideMethodRef := MethodRef;
end;

procedure Exe(Self : in out Instance;
M    : in Message.Class_Reference) is
begin
Ada.Text_IO.Put_Line(PACKAGE_NAME & ".Exe Tick=" &
Integer'Image(Self.Tick));
--     Message.Print(M.all);

--Problem area:--
Self.OverrideMethodRef(M.all, Self.Argument); --Compilation error!
-----------------
end;
...
end Action.Override;

Override actions are initialized like this:

Initialize(An_Action, 200, 3.3, Message.M1.Put_A'access);

Compilation error:
------------------
gcc says:

action-override.adb:100:31: expected private type "MessageType" defined
at action-override.ads:35
action-override.adb:100:31: found type "Instance'Class" defined at
message.ads:44
Questions:
----------
I have a class-wide variable (M.all) and want to pass it to a procedure
(Message.M1.Put_A) taking a specific instance (Message.M1.Instance) of
the class.

1. Why does this not work?

2. Shouldn't a conversion from T11 stored in a T1'Class variable, to a
T11 variable be OK of T11 is a child of T1 (checked during run-time)?

The information needed is of course present in M.all, otherwise
dispatching wouldn't be possible. (I have tested dispatching with the
call Message.Print(M.all) commented out in the example and i works
fine.)

Note that making every Put-procedure virtual is not an option since
they by nature are unique to each message.

3. Are there any problems connected to that I use an access to a
procedure?

4. Is the generic type MessageType causing the problem? The MessageType
is supposed to be a specific sub-class of Message, hence a member of
Message'Class so...

5. Have I designed completely wrong?

6. Do you have any suggestions on how to solve this problem in a good
way?

Your answers will be appreciated.

Merry Christmas etc!

/Per




             reply	other threads:[~2004-12-22 13:49 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-12-22 13:49 per [this message]
2004-12-22 15:17 ` OO problem: Performing actions on messages (very long, sorry) 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
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