comp.lang.ada
 help / color / mirror / Atom feed
From: Marin David Condic <nobody@noplace.com>
Subject: Re: Abstract Operations On A Tagged Record
Date: Mon, 01 Nov 2004 12:58:39 GMT
Date: 2004-11-01T12:58:39+00:00	[thread overview]
Message-ID: <3qqhd.16031$ta5.3884@newsread3.news.atl.earthlink.net> (raw)
In-Reply-To: <2uhsidF2ahq9fU1@uni-berlin.de>

Thanks for the response. As both you and Dimitry observed, I rather 
neglected to toss in the class parameter. I should have put in an 
example with a base class operation that looked like:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class) is abstract ;

Then the intent was to discuss the need to have child operations with 
different parameter profiles:

procedure Some_Op (The_Thing : in out Some_Tagged_Type_Child1 ; Parm1 : 
in Integer) is abstract ;

procedure Some_Op (The_Thing : in out Some_Tagged_Type_Child2 ; Parm1 : 
in Boolean; Parm_2 : in Float) is abstract ;

My understanding from your explanation is that I can't really get around 
having to fill in *something* for:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class) is abstract ;

but that overloading takes care of the other cases. I was hoping to 
avoid having a useless operation dangling around like that.

However, I had thought of the case you mention wherein I could provide 
another tagged type for the parameter list and do something like this in 
the base class:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class; Its_Parms 
: in Another_Tagged_Type'Class) is abstract ;

That sounds like a reasonable answer to the abstraction problem I had. I 
can identify the need for some parameters down the line without having 
to specify what they are in the base class. It keeps me from 
proliferating operations all over the place while allowing me to insist 
that a certain operation must be provided from anything inherited from 
the base class.

Thanks for the help.

MDC



Nick Roberts wrote:
> Marin David Condic wrote:
> 
>> Can someone clarify my understanding (perhaps again) on abstract 
>> operations and the implications as a class heierarchy is being 
>> constructed? Specifically, what I want is something like this:
>>
>> A base class has an abstract operation, but I may not yet know the 
>> data types of the parameters - or possibly even the number of 
>> parameters. ...
>> The base class wants to express the basic necessity of "Some_Op" but 
>> it really doesn't know if it will have 1, 2 or N parameters or of what 
>> type. My understanding is that if I express that as an abstract 
>> operation, when I get to the child class, I'll have to supply a real 
>> operation of the same name and same parameter profile.
> 
> 
> Correct.
> 
>> (Or can I use a different parameter profile & satisfy the need for a 
>> concrete implementation of the abstract op? 
> 
> 
> No.
> 
>> My recollection is the compiler whines about it or creates an 
>> overloading. Is this correct?
> 
> 
> Correct. (The compiler whines ;-)
> 
>> I realize I can make another procedure "Some_Op" with a different 
>> parameter list and that overloading will take care of me, but then I 
>> didn't really need the abstract procedure in the first place, did I? 
>> It becomes unnecessary baggage that you have to fill in just because 
>> its there, but you have no intention of using it.
> 
> 
> Worse than that, you have no dynamic dispatching, which is the whole
> point of using a tagged type in the first place. Disaster.
> 
>> Do I understand this correctly? Is there away around it?
> 
> 
> The solution is simple, Marin. You use /two/ type hierarchies, one to
> represent the primary objects, and a secondary one to represent the
> detailed parameters of the primitive operation in question.
> 
> For example, suppose we have a primary hierarchy of shapes, and we
> want a primitive operation transforming a shape according to a set
> of parameters that depends on the shape (and the kind of
> transformation):
> 
>   type Root_Shape_Type is abstract tagged private;
> 
>   type Transformation_Spec is abstract tagged private;
> 
>   function Transform (Shape: in Root_Shape_Type;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class is abstract;
> 
>   Transformation_Error: exception;
> 
> Note carefully that Transform is a primitive operation of the primary
> type Root_Shape_Type. The Spec parameter is of a class wide type, and so
> is the result (since a transformation might produce a different kind of
> shape).
> 
> We could then declare some transformations, such as:
> 
>   type Rotation is new Transformation_Spec with
>      record
>         Angle: Radians;
>      end record;
> 
>   type Translation is new Transformation_Spec with
>      record
>         Offset: Surface_Offset;
>      end record;
> 
> and we might declare a polygon, say, as follows:
> 
>   type Polygonal_Shape is new Root_Shape_Type with private;
> 
>   function Points (Shape: in Polygonal_Shape) return Point_Vector;
> 
>   ... -- other polygon operations
> 
>   function Transform (Shape: in Polygonal_Shape;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class;
> 
> The body of the Transform function for polygons would have to test the
> actual type of the Spec parameter to determine which tranformation to
> perform:
> 
>   function Transform (Shape: in Polygonal_Shape;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class is
>   begin
>      if Spec in Rotation then
>         declare
>            Rot_Spec:   constant Rotation := Rotation(Spec);
>            Center:     constant Point := Centerpoint(Shape);
>            Old_Points: constant Point_Vector := Points(Shape);
>            New_Points: Point_Triple(Old_Points'Range);
>         begin
>            for P in Old_Points'Range loop
>               New_Points(P) :=
>                  Rotate( Old_Points(P), Center, Rot_Spec.Angle );
>            end loop;
>            return To_Polygon(New_Points);
>         end;
>      elsif Spec in Translation then
>         ...
>      else
>         raise Transformation_Error; -- unrecognized transformation
>      end if;
>   end Transform;
> 
> I think it is interesting to note that some languages, such as Cecil,
> provide a way to select an operation's implementation (body) on two or
> more parameters, rather than just one. Cecil is a very interesting
> language (but not yet mature enough for real use, I think).
> 
> Nevertheless, Ada's lowly single selection still permits new shapes to
> be added to a program without having to worry about how this affects
> other parts of the program (in general), and this could be very useful.
> 
> Note also that you might possibly wish to swap the roles of shape and
> transformation, so that Transform becomes a primitive operation of
> Transformation_Spec (instead of Root_Shape_Type), and bodies of the
> function have to test for different shapes. This would allow you to
> add new transformations in a very independent manner.
> 
> HTH
> 

-- 
======================================================================
Marin David Condic
I work for: http://www.belcan.com/
My project is: http://www.jsf.mil/NSFrames.htm

Send Replies To: m   o   d   c @ a   m   o   g
                    c   n   i       c   .   r

     "Power corrupts.  Absolute power is kind of neat"
         -- John Lehman, Secretary of the Navy 1981-1987
======================================================================



  reply	other threads:[~2004-11-01 12:58 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-30 13:04 Abstract Operations On A Tagged Record Marin David Condic
2004-10-30 14:34 ` Dmitry A. Kazakov
2004-10-30 16:07 ` Nick Roberts
2004-11-01 12:58   ` Marin David Condic [this message]
2004-11-01 18:09     ` Nick Roberts
2004-11-01 22:27       ` Marin David Condic
2004-11-06 13:17       ` Marin David Condic
replies disabled

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