OO problem: Performing actions on messages (very long, sorry)
From: per (commander_at_death-star.com)
Date: 12/22/04
- Next message: Alex R. Mosteo: "Re: ANNOUNCE: GNAT Programming System 2.1.0"
- Previous message: Arnaud Charlet: "ANNOUNCE: GNAT Programming System 2.1.0"
- Next in thread: Dmitry A. Kazakov: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Dmitry A. Kazakov: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Martin Krischik: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Nick Roberts: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 22 Dec 2004 05:49:54 -0800
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
- Next message: Alex R. Mosteo: "Re: ANNOUNCE: GNAT Programming System 2.1.0"
- Previous message: Arnaud Charlet: "ANNOUNCE: GNAT Programming System 2.1.0"
- Next in thread: Dmitry A. Kazakov: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Dmitry A. Kazakov: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Martin Krischik: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Reply: Nick Roberts: "Re: OO problem: Performing actions on messages (very long, sorry)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|