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,e94d0e47489de27d X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1995-01-25 10:57:01 PST Newsgroups: comp.lang.ada Path: nntp.gmd.de!newsserver.jvnc.net!yale.edu!noc.near.net!inmet!henning!stt From: stt@henning.camb.inmet.com (Tucker Taft) Subject: Re: Question: Extensible subobject? Message-ID: Sender: news@inmet.camb.inmet.com Organization: Intermetrics, Inc. References: <3fpbso$6g2@motss.newpaltz.edu> Date: Wed, 25 Jan 1995 18:57:01 GMT Date: 1995-01-25T18:57:01+00:00 List-Id: In article <3fpbso$6g2@motss.newpaltz.edu>, Martin Ruckert wrote: >I don't know enough about Ada to find the best solution to the following >problem using Ada. I would be interested in a solution to include it in a >comparison of major object oriented languages. So, someone out there >might know the answer. > >Problem: >An interactive application presents texts to the user in windows. >Most of the texts are read only (help, messages, menus). The base class >is RO_Text, it has methods to provide read access to the text. Presumably you would have something like this: type RO_Text is tagged private; function Get_Text( Text : RO_Text; Start, End : Position) return String; ... >A subclass of RO_Text is Edit_Text, which defines some additional >data fields to do a more complex storage management and it provides >additional methods to allow changes to the text (e.g. insert a >character). Something like ... type Edit_Text is new RO_Text with private; procedure Put_Text( Text : in out Edit_Text; Start, End : in Position; New_Text : in String); ... >The base class for windows is RO_Window, it specifies a field t to be a >pointer to an RO_Text and has methods to perform all the updating of >the screen to make the text visible. And... type Text_Ptr is access all RO_Text'Class; type RO_Window is tagged private; procedure Refresh(Win : in out RO_Window); function Window_Text(Win : RO_Window) return Text_Ptr; procedure Set_Window_Text( Win : in out RO_Window; Text : access RO_Text'Class); ... >I want the class Edit_Window to be a subclass of RO_Window. Edit_Window needs >additional methods to service requests to change the text shown (e.g. >inserting a character). This new methods will update the screen and it >should forward the message to its text. type Edit_Window is new RO_Window with private; procedure Edit(Win : in out Edit_Window; Info : Whatever); -- forwards message to Text object >I can create an Edit_Text and store the pointer to it in the field t of the >Edit_Window. So the text subobject has methods to perform the changes, but >the type of t is a pointer to a RO_Text. Will it allow access to the >necessary methods of the Edit_Text? Presuming the type of the field t is an access (aka "pointer") type like Text_Ptr above, then it can be used to store a pointer to any descendant of RO_Text, including Edit_Text. However, whether you choose to reuse the space for this pointer would best be hidden from the client anyway. If you require that an Edit_Window be given a pointer to a writable text object, then you should enforce that in the Set_Window_Text operation, and provide an additional function, perhaps "Editable_Window_Text" that directly returns an access-to-Edit_Text'class. This could be accomplished roughly as follows: -- add routine to return writable text pointer type Editable_Text_Ptr is access all Edit_Text'Class; function Editable_Window_Text( Win : Edit_Window) return Editable_Text_Ptr; -- override Set_Window_Text to check that the actual -- parameter is an access-to-Edit_Text'Class procedure Set_Window_Text( Win : in out Edit_Window; Text : access RO_Text'Class); ... procedure Set_Window_Text( Win : in out Edit_Window; Text : access RO_Text'Class) is begin if Text.all not in Edit_Text'Class then raise Editable_Text_Required; end if; -- Pass the buck to parent's routine Set_Window_Text(RO_Window(Win), Text); end Set_Window_Text; -- body of Editable_Window_Text does the conversion function Editable_Window_Text( Win : Edit_Window) return Editable_Text_Ptr is begin return Editable_Text_Ptr(Window_Text(Win)); -- Explicitly convert result returned by Window_Text. -- Tag check performed automatically at run-time end Editable_Window_Text; >If I use a type conversion on t it needs runtime overhead for checking. The overhead is very small (just a few instructions). You could avoid it by not trying to reuse the same pointer for the pointer to the editable window (or by suppressing the check). >Type conversions should be avoided if anyway? Type conversions should be avoided, but they are inevitable in certain cases, particularly if you violate "pure" subtyping when you extend. For example, in this case you are presumably not allowing the text object associated with an Edit_Window to be read-only. That violates "pure" subtyping, in that you cannot fully substitute an Edit_Window for an RO_Window. Such violations are relatively common in many "real" systems. However, you could take steps to minimize it, by eliminating the Set_Window_Text operation, and only allowing the text object to be set when the window is first constructed. Having different constructors is not genereally considered a violation of pure subtyping. By the way, in Ada 9X, a "constructor" for a type is simply a function or procedure that produces a result of the type (as a return value, a returned pointer, an OUT parameter, etc.). >I would rather in Edit_Window redefine the type of t to be >a pointer to Edit_Text. This enables the compiler to check that my >assignments to t are correct and spares the type conversion and the test >associated with it later. > >Is it possible ?? How to handle it best ?? This is certainly possible. Simply add another field of the appropriate type, rather than reusing the inherited field. However, in the sense described above, an Edit_Window is not a pure subtype of an RO_Window, so it might be better to make them both derived from some common abstract Window type. Then you can give them each their own field for pointing to a text object, with exactly the "right" type. >Martin > >Address: ruckert@mcs.newpaltz.edu -Tucker Taft stt@inmet.com Intermetrics, Inc. Cambridge, MA 02138