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,56dbd715fa74735a X-Google-Attributes: gid103376,public From: adam@irvine.com Subject: Re: Mutually dependent private types Date: 1998/05/22 Message-ID: <6k4b7t$vhn$1@nnrp1.dejanews.com> X-Deja-AN: 355577709 X-Http-User-Agent: Mozilla/3.0 (X11; I; Linux 2.0.18 i586) Organization: Deja News - The Leader in Internet Discussion X-Article-Creation-Date: Fri May 22 17:05:01 1998 GMT 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. > > 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. OK, this is helpful. It looks like it should work in my case. Here's the trivial thing I missed: if I write code like this, I can also add this compilation unit with Adam.P2; package P2 renames Adam.P2; so that I don't have to go back and modify all the other packages that used P2. What I hadn't mentioned in my previous post was that I had an objection to making major changes in the structure of P2. In my real situation, I had already written P1 and P2, and there were no mutual dependencies, and everything was fine. However, I needed to add a new operation to P1; this new function would operate on P1.T1 and needed access to the representation of P1.T1, but also needed to take an object of type P2.T2 as a parameter. What bothered me was that adding this functionality to P1 would require me to make such a major structural change to P2 that I'd have to modify every module that with'ed P2, which in this case is about a hundred modules. This was hard for me to swallow, particularly since I wasn't changing the functionality of P2 at all. But I forgot about the library-level rename, which lets me avoid having to make such wholesale changes. (I still have to recompile everything that with's P2, but this isn't as obnoxious.) IMHO, it still would be more ideal, and more in keeping with software engineering principles, if I were able to add new functionality to P1 without touching P2. Granted, we can't expect this to happen in every case, but if there are reasonable extensions to the language that would help in cases like this, I think they should be considered next time the language is enhanced. > I read John's paper, but I don't find his argument convincing. Doesn't the > following code solve the putative with'ing "problem"? I think John's objection to this solution is that it requires a runtime check to make sure the second parameter has the correct type. Also, one could object on philosophical grounds that requiring the two packages to be children of a common parent isn't appropriate for packages that really don't have much of a common purpose. (Then again, I suppose that with every language there are cases that require one to write code that goes against software engineering philosophy.) -- Adam > > --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; > -----== Posted via Deja News, The Leader in Internet Discussion ==----- http://www.dejanews.com/ Now offering spam-free web-based newsreading