comp.lang.ada
 help / color / mirror / Atom feed
From: jsa@organon.com (Jon S Anthony)
Subject: Re: Q. about Inheritance in Ada95
Date: 1996/07/03
Date: 1996-07-03T00:00:00+00:00	[thread overview]
Message-ID: <JSA.96Jul2220809@organon.com> (raw)
In-Reply-To: 4rc2q8$b84@portal.gmu.edu


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





  parent reply	other threads:[~1996-07-03  0:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1996-07-02  0:00 Q. about Inheritance in Ada95 Wajdi H Al-Jedaibi (INFT)
1996-07-02  0:00 ` Robert A Duff
1996-07-03  0:00   ` Mark A Biggar
1996-07-03  0:00     ` Robert A Duff
1996-07-03  0:00 ` Jon S Anthony [this message]
1996-07-03  0:00 ` Tucker Taft
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox