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-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,c9a5d6b3975624e1 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2002-10-03 23:01:13 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!logbridge.uoregon.edu!news.stealth.net!news.stealth.net!ngpeer.news.aol.com!cyclone1.gnilink.net!wn11feed!worldnet.att.net!204.127.198.203!attbi_feed3!attbi.com!sccrnsc03.POSTED!not-for-mail From: tmoran@acm.org Newsgroups: comp.lang.ada Subject: Re: OO in Ada References: X-Newsreader: Tom's custom newsreader Message-ID: NNTP-Posting-Host: 12.234.13.56 X-Complaints-To: abuse@attbi.com X-Trace: sccrnsc03 1033711272 12.234.13.56 (Fri, 04 Oct 2002 06:01:12 GMT) NNTP-Posting-Date: Fri, 04 Oct 2002 06:01:12 GMT Organization: AT&T Broadband Date: Fri, 04 Oct 2002 06:01:12 GMT Xref: archiver1.google.com comp.lang.ada:29510 Date: 2002-10-04T06:01:12+00:00 List-Id: >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 ...