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.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,56dbd715fa74735a X-Google-Attributes: gid103376,public From: John Volan Subject: Re: Mutually dependent private types Date: 1998/05/22 Message-ID: <3565B105.9BFB4788@ac3i.dseg.ti.com>#1/1 X-Deja-AN: 355601523 Content-Transfer-Encoding: 7bit References: <6k25ra$6j7$1@nnrp1.dejanews.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Organization: Raytheon Systems Company, Advanced C3I Systems Newsgroups: comp.lang.ada Date: 1998-05-22T00:00:00+00:00 List-Id: Matthew Heaney wrote: > > Here's is a solution to your problem. > > 1) No private child package is required. Move the representation of T1 and > T2 up into the private region of a common parent package. Adam's two types didn't need to know about each other's implementations. Even if you had the P1.T1 type holding a reference (access) to a P2.T2 object, from the perspective of package P1, P2.T2 could still look like a private type. And vice versa in the other direction. > 2) Types T1 and T2 privately derive from the respective rep types. Each > type, because it's in a child package of package containing both rep types, > has direct visibility to the rep of the other type. > > 3) The mutual dependency in operations is effected by making the other type > have type Root'Class, in the spec. In the body, just downcast the object > to the representation type. Of course, the compiler can't verify > statically that the object is really of the required type, but you'll find > out at runtime, because a tag check happens when you downcast. See http://bluemarble.net/~jvolan/WithingProblem/FAQ.html#strong_typing, where I describe how the with-ing problem can be avoided, at the expense of Ada95's static strong typing checks, by deriving all your object classes from some universal root type (Objects.Object_Type was my suggestion). > This is out-of-the-box Ada 95. No complex language extensions or > Unchecked_Conversion or implementing types using access types is required. Yes, but unfortunately it forces Ada95 to act a lot like Smalltalk. The programmer presumably knows statically that O1 is always supposed to be a T1 and O2 is always supposed to be a T2, but this coding style prevents the compiler from knowing that. It is very possible that someone could write code that tried to pass something other than a T2 into P1.Op1. Such code would of course be a bug, but it wouldn't be caught until the call to P1.Op1 was actually executed and the tag-check was performed. Depending on the testing scheme used during development, this call may or may not get executed. So this bug could actually go undetected during testing and wind up being reported by an irate end user. > I read John's paper, but I don't find his argument convincing. Doesn't the > following code solve the putative with'ing "problem"? [snip Matt's example] The *_Rep types aren't even necessary, if you're going to go with the universal root type strategy: package Adam is type Root is abstract tagged null record; end Adam; package Adam.P1 is type T1 is new Root with private; procedure Op1 (O1 : in out T1; O2 : in Root'Class); -- precondition: O2 in P2.T2'Class function Get_F (O1 : in T1) return Float; private type T1 is new Root with record F : Float; end record; end Adam.P1; with Adam.P2; package body Adam.P1 is procedure Op1 (O1 : in out T1; O2 : in Root'Class) is begin O1.F := Float (P2.Get_I(P2.T2'Class(O2))); end Op1; function Get_F (O1 : in T1) return Float is begin return O1.F; end Get_F; end Adam.P1; package Adam.P2 is type T2 is new Root with private; procedure Op2 (O2 : in out T2; O1 : in Root'Class); -- precondition: O1 in P1.T1'Class function Get_I (O2 : in T2) return Integer; private type T2 is new Root with record I : Integer; end record; end Adam.P2; with Adam.P1; package body Adam.P2 is procedure Op2 (O2 : in out T2; O1 : in Root'Class) is begin O2.I := Integer (P1.Get_F(P1.T1'Class(O1))); end Op2; function Get_I (O2 : in T2) return Integer is begin return O2.I; end Get_I; end Adam.P2; with Adam.P1; with Adam.P2; procedure Adam.Test is O1 : P1.T1; O2 : P2.T2; begin P1.Op1 (O1, O2); P2.Op2 (O2, O1); end Adam.Test; -- Signature volanSignature = new Signature ( /*name: */ "John G. Volan", /*employer: */ "Raytheon Advanced C3I Systems, San Jose", /*workEmail: */ "johnv@ac3i.dseg.ti.com", /*homeEmail: */ "johnvolan@sprintmail.com", /*selfPlug: */ "Sun Certified Java Programmer", /*twoCents: */ "Java would be even cooler with Ada95's " + "generics, enumerated types, function types, " + "named parameter passing, etc...", /*disclaimer:*/ "These views not packaged in COM.ti.dseg.ac3i, " + "so loading them throws DontQuoteMeError. :-)" );