comp.lang.ada
 help / color / mirror / Atom feed
From: tmoran@acm.org
Subject: Re: OO in Ada
Date: Fri, 04 Oct 2002 06:01:12 GMT
Date: 2002-10-04T06:01:12+00:00	[thread overview]
Message-ID: <I8an9.29526$FO4.7762@sccrnsc03> (raw)
In-Reply-To: mailman.1033697703.29112.comp.lang.ada@ada.eu.org

>Extension of this class to Thick_Pen should, according to me, result in a
>class having the form:
>
>+-------------------------------------------+
>| Thick_Pen                                 |
>+-------------------------------------------+
>| X         : Integer;                      |
>| Y         : Integer;                      |
>| Color     : Color_Type;                   |
>| Thickness : Positive;                     |
>+-------------------------------------------+
  No.  A Thick_Pen is a Pen with a thickness.
    type Thick_Pen is new Pen with record
      Thickness : Positive;
    end record;
The original Pen may (does, in this case) have an X,Y (or perhaps
R,Theta) and Color, and perhaps also a Window_Handle and who knows what
else, but those details are not a concern of Thick_Pen.
  If code for a Thick_Pen really does need to get at the internal,
private, record components such as X or Y, then Thick_Pen will have to
be declared in a child of the package that declares Pen.  If you have
good abstraction and separation of concerns, that shouldn't be necessary.

>| --=== inherited from Pen_Class ===--      |
>| procedure Move_To(This : in out Pen;      |
>|                   X    : in     Natural;  |
>|                   Y    : in     Natural); |
>| -- move the pen to the specified location |
>| --  without drawing                       |
  No.  What's inherited is a compiler-created
   procedure Move_To(This : in out Thick_Pen;
                     X    : in     Natural;
                     Y    : in     Natural);
unless of course you specifically override that with your own
brand new Move(Thick_Pen).  Usually in that case you would have something
like:
   procedure Move_To(This : in out Thick_Pen;
                     X    : in     Natural;
                     Y    : in     Natural) is
   begin
     -- do something special for Thick_Pens that isn't done for Pens
     Move_To(Pen(This), X,Y);  -- move the underlying Pen
   end Move_To;

>|                                           |
>| function New_Pen(X     : Natural;         |
>|                  Y     : Natural;         |
>|                  Color : Color_Type)      |
>| return Pen_Access;                        |
>| -- returns access to an initialised Pen   |
  This function can't be inherited, since it could only initialize
a Pen, but wouldn't know what to do about the extra attributes of a
new Thick_Pen.  So you will *have to* write your own
   function New_Pen(X     : Natural;
                    Y     : Natural;
                    Color : Color_Type)
   return Thick_Pen_Access;
Here you start to get in trouble since you have no way to initialize
a Pen's parts except by getting a pointer to a Pen.  It would have
been much simpler if New_Pen returned a Pen or a Thick_Pen rather
than an access to one.  Of course you would still need a specifically
written "New_Pen(...) return Thick_Pen", since you can't inherit
New_Pen(...) return Pen since it doesn't know enough.  This New_Pen
function, since it doesn't have a Thickness parameter, will have to
return a Thick_Pen with some default value for Thickness.

>| function New_Thick_Pen                    |
>|    (X         : Natural;                  |
>|     Y         : Natural;                  |
>|     Color     : Color_Type;               |
>|     Thickness : in Positive)              |
>| return Thick_Pen_Access;                  |
>| -- returns access to initialised Thick_Pen|
  This is indeed a brand new function to create new Thick_Pens with
non-default values of Thickness.

> 1.   All the texts I can find which deal in any degree at all with OO in Ada
> teach that the tagged record in an object declaration should be 'private'.
> When you follow this line, a derived class does not have direct access to
> the object attributes of the base class, i.e. _there_is_no_inheritace_.
  The attributes should normally be private because nobody has a Need To
Know about them.  A drawing program shouldn't need to know about the
attributes of a Pen - just how to use one.  Code to Move and Draw and
whatever with a Thick_Pen shouldn't need to know either - just that
there exists a Pen object that you can create, move, and draw.  If
Thick_Pen, or the drawing program, need to know things like the Color,
or position, there should be functions
  function Color_Of(This : Pen) return Color;
  function Position_Of(This : Pen) return Position_Type;
Those functions will also be inherited by Thick_Pen, presuming there's
no special handling required to find a Thick_Pen's color or position.
If some special stuff *is* needed for a Thick_Pen, an adjustment
to Position based on Thickness, say, then you'll write a new
  function Position_Of(This : Thick_Pen) return Position_Type;
to override the inherited one.

>:)  However, if in a program 'use'ing the child package of 'Thick_Pen' (and
>not mentioning the base package of 'Pen') I make a call to the routine
>'Draw' with an actual parameter of the type 'Pen' I get a compiler error
>message to the effect that 'Draw' is not visible.  In other words, Thick_Pen
>has not inherited the operation Draw for 'Pen'
  Wrong.  There is an inherited Draw - it takes a parameter of type
Thick_Pen.  If you want to call a different Draw, one that takes a parameter
of type Pen, then you'll need to give a full name or have a Use clause
for the package containing *that* Draw.

> 4.  Further along that line, Thick_Pen does not inherit the type Pen so I
  Your package that declares Thick_Pen, declares Thick_Pen, not Pen.
It must 'with' Pen_Package of course in order to be able to say "is new Pen",
and that 'with' brings along function Move(This : Pen), etc.  The
"is new Pen" creates brand new functions Move(This : Thick_Pen) etc.  If
you don't override those brand new functions, the compiler will implement
them as calls to Move(This : Pen) etc.

package Pen_Package is
  type Pen is tagged private;
  procedure Move_To(This : in out Pen;
                    X    : in     Natural;
                    Y    : in     Natural);
  -- Draw, New_Pen, and everything else any outsiders need know
private
  type Pen is tagged record
    R,Theta : Float := 0.0;  -- just to be weird
    Color : Colors:= Red;
    Handle : Windows.Handles := Windows.Null_Handle;
    -- and anything else as appropriate
  end record;
end Pen_Package;

with Pen_Package;
package Thick_Pen_Package is

  type Thick_Pen is Pen_Package.Pen with private;

  Out_Of_Ink : Exception;

  procedure Draw_To(This : in out Thick_Pen;
                    X    : in     Natural;
                    Y    : in     Natural);
    -- every Draw operation uses ink, amount depending on thickness of pen
    -- raises Out_Of_Ink if it runs out of ink.

  -- by inheritance from Pen:
  -- procedure Move_To(This : in out Thick_Pen;
  --                   X    : in     Natural;
  --                   Y    : in     Natural);

private
  type Thick_Pen is Pen_Package.Pen with record
    Thickness : Positive := 0;
    Remaining_Ink : Positive := 100;
  end record;
end Thick_Pen;

package body Thick_Pen_Package is
  procedure Draw_To(This : in out Pen;
                    X    : in     Natural;
                    Y    : in     Natural) is
  begin
    if This.Remaining_Ink = 1 then raise Out_Of_Ink;end if;
    Remaining_Ink := Remaining_Ink - Thickness;
    Pen_Package.Draw_To(Pen_Package.Pen(This), X, Y);
  end Draw_To;
end Thick_Pen_Package;
  ...
  T : Thick_Pen;
  ...
  Move_To(T, 10,10);  -- uses compiler created, ie, inherited, Move_Pen
  Draw_To(T, 20,20);  -- use explicitly created Draw_To

> not use the intuitive 'object.method' syntax for making calls to and object.
  Because some of us find it not at all intuitive? ;)
In addition to advantages mentioned by others, Ada lets you have multiple
tagged type parameters, which is much nicer when no one parameter is
special:
  type Object is tagged record
    X,Y : Float;
  end record;
  function Distance(A,B : Object) return Float;
  ...
  if Distance(Car, Truck) < 1.0 then ...
vs
  if Car.Distance(Truck) < 1.0 then ...



  parent reply	other threads:[~2002-10-04  6:01 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-10-04  2:14 OO in Ada Rick Duley
2002-10-04  2:55 ` Jim Rogers
2002-10-04 17:35   ` Hyman Rosen
2002-10-05  0:20     ` Jim Rogers
2002-10-05 23:38       ` Dmitry A.Kazakov
2002-10-05 15:25         ` Jim Rogers
2002-10-06 21:37           ` Dmitry A.Kazakov
2002-10-06  2:18       ` Hyman Rosen
2002-10-06  3:00         ` Jim Rogers
2002-10-08 21:08           ` Gisle Sælensminde
2002-10-04  3:37 ` Chad R. Meiners
2002-10-04  5:32 ` Simon Wright
2002-10-04  6:01 ` tmoran [this message]
2002-10-04 15:05 ` Matthew Heaney
2002-10-05  2:14 ` SteveD
2002-10-05  8:54   ` Preben Randhol
2002-10-07 14:10   ` Matthew Heaney
2002-10-07 19:52     ` Jeffrey Carter
2002-10-08 21:18     ` Dmitry A.Kazakov
2002-10-08  9:53 ` John McCabe
2002-10-08 15:37   ` Matthew Heaney
2002-10-08 16:47     ` Georg Bauhaus
2002-10-08 17:48       ` Matthew Heaney
2002-10-08 17:16     ` Warren W. Gay VE3WWG
2002-10-08 17:58       ` Matthew Heaney
2002-10-09 16:59         ` Warren W. Gay VE3WWG
2002-10-08 10:21 ` Preben Randhol
  -- strict thread matches above, loose matches on Subject: below --
1998-05-15  0:00 Gisle S{lensminde
replies disabled

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