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, T_FILL_THIS_FORM_SHORT 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: matthew_heaney@acm.org (Matthew Heaney) Subject: Re: Mutually dependent private types Date: 1998/05/21 Message-ID: #1/1 X-Deja-AN: 355472281 Content-Transfer-Encoding: 8bit References: <6k25ra$6j7$1@nnrp1.dejanews.com> Content-Type: text/plain; charset=ISO-8859-1 Organization: Network Intensive Mime-Version: 1.0 Newsgroups: comp.lang.ada Date: 1998-05-21T00:00:00+00:00 List-Id: In article <6k25ra$6j7$1@nnrp1.dejanews.com>, adam@irvine.com wrote: (start of quote) I've run into another problem trying to get something implemented in Ada 95. This problem seems superficially similar to John Volan's with-ing problem, but I don't think it's quite the same. (1) If I want to have two private types in two separate packages whose *implementations* are mutually dependent on each other, this is easy to do, if we're willing to make the private types accesses: (end of quote) Done. (start of quote) (2) Another mutual-dependency situation is this: Suppose I want to have two types T1 and T2 in two different packages, and I want to provide operations on T1 that take T2 as a parameter, and operations on T2 that take T1 as a parameter. You can't do this by declaring T1 and T1's operations in the same package and do the same for T2, since then the two package specs would have to be mutually dependent. However, you can solve this problem by separating the type definition from the operations in two separate packages (preferably using child units): (end of quote) Done. (start of quote) (3) But what happens if you want to do both (1) and (2)? Now the whole thing seems to break down. If you try to do both of the above, something like: (end of quote) Done. 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. 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. This is out-of-the-box Ada 95. No complex language extensions or Unchecked_Conversion or implementing types using access types is required. I read John's paper, but I don't find his argument convincing. Doesn't the following code solve the putative with'ing "problem"? Matt --STX package body Adam.P1 is procedure Op1 (O1 : in out T1; O2 : in Root'Class) is begin O1.F := Float (T2_Rep (O2).I); end Op1; end Adam.P1; 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 private type T1 is new T1_Rep with null record; end Adam.P1; package body Adam.P2 is procedure Op2 (O2 : in out T2; O1 : in Root'Class) is begin O2.I := Integer (T1_Rep (O1).F); end Op2; end Adam.P2; 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 private type T2 is new T2_Rep with null record; end; with Adam.P1; with Adam.P2; procedure Adam.Test is O1 : P1.T1; O2 : P2.T2; use P1, P2; begin Op1 (O1, O2); Op2 (O2, O1); end Adam.Test; package Adam is pragma Pure; -- the package, not Adam! type Root is abstract tagged null record; private type T1_Rep is new Root with record F : Float; end record; type T2_Rep is new Root with record I : Integer; end record; end Adam;