From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 20 Aug 93 17:49:38 GMT From: cis.ohio-state.edu!magnus.acs.ohio-state.edu!math.ohio-state.edu!darwin.s ura.net!source.asset.com!cernosek@ucbvax.Berkeley.EDU (Gary J. Cernosek) Subject: Performing I/O on Private Types in Ada 9X (Was Re: OO Preprocessor for Ada) Message-ID: <1993Aug20.174938.40429@source.asset.com> List-Id: >Obviously you're right, I was just asleep in the front row again. > >I guess what this example triggered was painful memories of trying >to provide text_io capabilities when you declare a limited private type. >Does anyone have an elegant example of how to do this with 9X with tagged >types and text_io generics? > >I guess to further define the problem, using this running example, >how can I provide a text_io print capability of an object of type X.Object? >(i.e. how do I print An_Object directly?). Well, by the very nature of An_Object being declared of a private type, you can't -- and the fact that this private type happens to be tagged doesn't change that. In other words, an ordinary piece of client code is afforded no more visibility into a tagged object's private structure than is realized by a non-tagged object. While an ordinary program unit may indeed extend a tagged type with new components, the program unit that derives the new type does not gain visibility into the original type's private part simply by doing such a type extension. But fear not, for your "painful memories" may be disposed of by an entirely different feature of Ada 9X, that being the _child library unit_. A child library unit is a separately compiled program unit that, among other things, can "see" into the private structure of its parent package. Such a construct allows us to effectively add declarations to an existing package without requiring modification to the original package itself. Much as tagged types allow us to extend the set of components defined for an existing record type, child library units allow us to extend the set of declarations defined by an existing package. Now although I've used child units to implement inheritance hierarchies, I haven't yet applied them to I/O problems. But for the sake of addressing this key problem in Ada 83, I'll give it a shot (Tucker, watch out for me, and jump in any time...). To re-establish context, I'll re-specify the example package used in earlier postings: package X is -- Represents a class X identified in OOA/OOD type Object is tagged limited private; -- Represents a "root class" procedure Create (Instance : in out Object); -- "constructor" A1 : in Integer); procedure Modify (Instance : in out Object; -- "modifier" A1 : in Integer; function P1 (Instance : Object) return Integer; -- (direct) "selector" private type Object is tagged record A1 : Integer; end record; end X; (Note that I changed each identifier P1 to A1, suggesting that the components of the tagged record represent an object's _Attributes, and that direct selector functions can be simply named accordingly.) Now, consider the following child library unit created from the parent package X shown above: package X.IO is procedure Print_Attributes (Instance : in Object); -- the type Object is directly visible from the parent unit X end X.IO; ----------------------------------------------------- with Text_IO; package body X.IO is procedure Print_Attributes (Instance : in Object) is -- Could instantiate Text_IO.Integer_IO instead of using 'IMAGE below begin Text_IO.Put ("The value of A1 is "); Text_IO.Put ( Integer'IMAGE(Instance.A1) ); -- A1 directly visible -- Could print other attributes if they existed end Print_Attributes; end X.IO; Note that the child unit is afforded _direct_ visibility to all of its parent's specifications. This is why the formal parameter for Print_Attributes need not reference the type as X.Object. But to really address Ken's questions on I/O, the child's _body_ has direct visibility to its parent's _private_ declarations as well. For those readers familiar with C++, child library units provide the "protected" form of visibility control defined by classes, which gives derived classes direct visibility into their parents' otherwise hidden members. Note, however, that in C++, the class designer must decide which members are to be "protected," whereas in Ada 9X, the "subclass" designer makes the decision. This is, I think, a most significant enhancement to Ada 83's sometimes overly restrictive visibility rules regarding packages with private parts. But maybe what's even more notable about using child library units in this way is that the original (parent) package X need not ever be concerned with the often unstable and non-portable nature of performing I/O in general. Thus, package designers can now readily build software components independently of any I/O that might be needed, knowing that such capabilities can be later developed and modified totally separately. For completeness, I'll revise the client code specified earlier, having it call upon the I/O child package to do its printing instead of within the client itself: with X.IO; -- Implicitly with's in X as well procedure Some_Client_With_IO_Removed is An_Object : X.Object; begin X.Create (Instance => An_Object, A1 => 7); X.Modify (An_Object, A1 => 3); X.IO.Print_Attributes (Instance => An_Object); end Some_Client_With_IO_Removed; Note that references to lower-level child units can become quite lengthy. In these cases, proper application of renaming (or the 'use' statement) would be in order. In any event, I think that this new capability of Ada 9X is most remarkable, especially for those like Ken Rowe who have been previously frustrated with Ada 83's "all-or-nothing" effect of private types. -- Gary J. Cernosek Fastrak Training Inc. Houston Office: (713) 280-4768 E-mail: cernosek@source.asset.com