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 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,ab090844d583ab0b X-Google-Attributes: gid103376,public From: jsa@organon.com (Jon S Anthony) Subject: Re: Q. about Inheritance in Ada95 Date: 1996/07/03 Message-ID: X-Deja-AN: 163403343 sender: news@organon.com (news) references: <4rc2q8$b84@portal.gmu.edu> organization: Organon Motives, Inc. newsgroups: comp.lang.ada Date: 1996-07-03T00:00:00+00:00 List-Id: In article <4rc2q8$b84@portal.gmu.edu> waljedai@site.gmu.edu (Wajdi H Al-Jedaibi (INFT)) writes: > Here is the question: > Does Ada 95 allows for task to be extended. It seems that this point No. Only tagged types may be extended. Well, unless you're talking about behavior in which case most types can be (just like in Ada83), but still not task types (or protected types). > If it does not, is there a way to to incorporate inheritance for ada > tasks? Kinda, sorta, maybe, depending on. What you can do is define a tagged type which contains a task type. You can then extend the tagged type. If you don't need to modify the tasking aspect, you can just add more attributes and/or operations. If you want/need to extend the thread capability, you have to play some games by defining a new task type for the extension and then including this as an attribute in the extension. In both cases, what you do is hide the tasks interface behind explicit operations on the "containing" type. In the cases we are talking about here, these will also (more than likely) be primitive operations capable of being dispatched to in the standard way. The implementations of the operations will call entries in the task interface of the contained task object of the object for which the dispatch occured. In the above scenario, you have what might be termed "active objects". Each instance of the tagged type will end up containing one or more threads of action. Another way of going about it is flip all aournd and treat the task type as the "major" type and parameterize it with access to classwide types representing the extendable types in which you are interested. Then in the bodies of the entries defined by the task type, you actually dispatch on the primitive operations "representing" them in the definitions of the various type extensions in the given classes. In this case you are directly interfacing with and accessing the task objects which just happen to have the ability to deal with hetergeneous collections of objects (the instances of the derivation trees subsumed by the class parameter(s)). Here's a silly example I hacked up (oops, four letter word here!) concerning the former technique about a year or so ago. Hmmm, looking this over I see that it also includes (in the implementation) examples of the latter technique as well... ---------------------------- First, we create a "base" active object thing (with some pretty contrived operations...): package Active_Objs is type Obj_Type ( Name : access String ) is tagged limited private; procedure Op1 ( Obj : Obj_Type ); function Name ( Obj : Obj_Type ) return String; private task type Action_Type ( Obj : access Obj_Type'Class ) is entry Op1; entry Name ( N : out String ); end Action_Type; type Obj_Type ( Name : access String ) is tagged limited record Actions : Action_Type(Obj_Type'Access); end record; end Active_Objs; package body Active_Objs is task body Action_Type is begin accept Op1 do null; -- op1 stuff... end Op1; accept Name ( N : out String ) do N := Obj.Name.all; end Name; end Action_Type; procedure Op1 ( Obj : Obj_Type ) is begin -- Op1 Obj.Actions.Op1; end Op1; function Name ( Obj : Obj_Type ) return String is Result : String(1..Obj.Name'Length); begin -- Name Obj.Actions.Name(Result); return Result; end Name; end Active_Objs; OK, anything in Active_Objs.Obj_Type'Class will have at least one independent thread of action -- that given by Actions_Type. So, we can now extend this with some new functionality which we assume needs more independent actions. with Active_Objs; package My_Active is type Obj_Type is new Active_Objs.Obj_Type with private; procedure Op2 ( Obj : Obj_Type ); function Id ( Obj : Obj_Type ) return Integer; private task type My_Actions_Type ( Obj : access Obj_Type'Class ) is entry Op2; entry Id ( I : out Integer ); end My_Actions_Type; type Obj_Type is new Active_Objs.Obj_Type with record My_Actions : My_Actions_Type(Obj_Type'Access); Id : Integer := 0; -- Holds the instances Object ID... end record; end My_Active; package body My_Active is -- Make generation of new OIDs task safe! -- protected Oids is procedure New_Id ( I : out Integer ); private Num : Integer := 0; end Oids; protected body Oids is procedure New_Id ( I : out Integer ) is begin Num := Num + 1; -- This update is guaranteed mutually exclusive! I := Num; end New_Id; end Oids; task body My_Actions_Type is begin accept Op2 do null; -- op1 stuff... end Op2; accept Id ( I : out Integer ) do if Obj.Id = 0 then Oids.New_Id(Obj.Id); -- Safely get a _unique_ ID end if; I := Obj.Id; end Id; end My_Actions_Type; procedure Op2 ( Obj : Obj_Type ) is begin -- Op2 Obj.My_Actions.Op2; end Op2; function Id ( Obj : Obj_Type ) return Integer is Result : Integer; begin -- Id Obj.My_Actions.Id(Result); return Result; end Id; end My_Active; Now, anything in My_Active.Obj_Type'Class will have at least _two_ independent threads of action. Certainly we are not _required_ to extend with extra threads of action, but if the actions we extend with are somehow required to be task safe, say, then this is an appropriate thing to do. Or, if the actions really are independent (say pistons moving affecting wheels turning or propellor turning) then this makes excellent sense. Now, as I say, the example here is really pretty lame, but just to finish it off, here is a use of the above: with My_Active; with Text_Io; use Text_Io; procedure Active is -- Since Obj is in My_Actions.Obj_Type'Class, it has both threads of -- action: the one from the base Active_Objs.Obj_Type and the one from -- the extension My_Active.Obj_Type... -- Obj : My_Active.Obj_Type (new String'("Mary")); begin My_Active.Op1(Obj); My_Active.Op2(Obj); Put_Line("My name is " & My_Active.Name(Obj)); Put_Line("My ID is " & Integer'Image(My_Active.Id(Obj))); end Active; $ gnatmake active.adb $ active My name is Mary My ID is 0 $ /Jon -- Jon Anthony Organon Motives, Inc. 1 Williston Road, Suite 4 Belmont, MA 02178 617.484.3383 jsa@organon.com