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 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,a8d137db7a5f6c81 X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: OO problem: Performing actions on messages (very long, sorry) Date: Wed, 22 Dec 2004 16:17:04 +0100 Organization: cbb software GmbH Message-ID: References: <1103723394.299024.314670@c13g2000cwb.googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: individual.net bF6LQlctzRVlw3h05cns3AQrLfybKndrzqIw/lJQd+nb53nY4= User-Agent: 40tude_Dialog/2.0.12.1 Xref: g2news1.google.com comp.lang.ada:7165 Date: 2004-12-22T16:17:04+01:00 List-Id: On 22 Dec 2004 05:49:54 -0800, per wrote: > 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. No. It is called "primitive operation". > The action Action.Override serves as an example in this post. This > action shall override a field in a message. One cannot override a field. Presently Ada's inheritance model is a type extension one. I.e. you can add a field, but not replace it with another. > 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. It is too late. Basically Put should be a primitive operation of Message...Instance. But when you pass a type as a formal generic parameter it is already frozen, which in other words means that you cannot define a primitive Put for it. You can do instead: generic type ArgumentType is private; -- Type extension package Message.Extender is type Instance is new Message.Instance with record Extension : ArgumentType; end record; procedure Put (M : Instance; A : ArgumentType); -- This is a "method" of Instance now procedure Put (M : Instance; A : ArgumentType) is begin M.Extension := A; end Put; > 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. It is not clear what are you going to achieve by that. It will not be dynamically polymorphic anyway as long as ArgumentTypes are not derived from the same base. So any possible gain = 0, IMO. > 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. If Put is not dispatching, what the use of it. In particular, why ":=" does not fit? > 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... It is definitely possible: package Messages is type Message is abstract new Ada.Finalization.Limited_Controlled with private; procedure Execute (This : in out Message) is abstract; type Messages_Queue is [abstract] new Ada.Finalization.Limited_Controlled with private; -- Abstract if there should be different implementations of queues procedure Enqueue ( Queue : in out Messages_Queue; Item : in out Message'Class ) [is abstract]; private ... end Messages; package Messages.My_Messages is type My_Message is new Message with private; procedure Finalize (This : in out Message); -- How to destruct procedure Initialize (This : in out Message); -- How to construct procedure Execute (This : in out Message); -- What to be done procedure Put_A (This : in out Message; A : Something); ... > Code [...] > > 1. Why does this not work? The expected type is MessageType as the compiler tells. MessageType is a generic formal type. The compiler does not know of any its possible relationships with Message.Instance. It is just a type: generic type MessageType is private; It is not even tagged. > 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)? Yes. If it is not, then Constraint_Error is propagated. > 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.) The information carrier is called "type tag". Each T'Class object has type tag in it. > 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? Basically, that it is not much OO. Primitive operations (virtual methods) are for that. > 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... Yes. > 5. Have I designed completely wrong? Mmm, it is too complex to my taste. I have an impression that you dealt too much with C++ templates. (:-)) > 6. Do you have any suggestions on how to solve this problem in a good > way? Message = Action to me. Even if there are some constraints like that several actions to be executed in a defined order, I would stick to this model using containers of actions. > Your answers will be appreciated. > > Merry Christmas etc! And Happy New Year! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de