From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_FILL_THIS_FORM_SHORT,WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,a8d137db7a5f6c81,start X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!postnews.google.com!c13g2000cwb.googlegroups.com!not-for-mail From: "per" Newsgroups: comp.lang.ada Subject: OO problem: Performing actions on messages (very long, sorry) Date: 22 Dec 2004 05:49:54 -0800 Organization: http://groups.google.com Message-ID: <1103723394.299024.314670@c13g2000cwb.googlegroups.com> NNTP-Posting-Host: 138.14.239.132 Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" X-Trace: posting.google.com 1103723398 20294 127.0.0.1 (22 Dec 2004 13:49:58 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Wed, 22 Dec 2004 13:49:58 +0000 (UTC) User-Agent: G2/0.2 Complaints-To: groups-abuse@google.com Injection-Info: c13g2000cwb.googlegroups.com; posting-host=138.14.239.132; posting-account=e84-wQ0AAADeDLnjH5yWqnRMVsJLfQJg Xref: g2news1.google.com comp.lang.ada:7157 Date: 2004-12-22T05:49:54-08:00 List-Id: 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