comp.lang.ada
 help / color / mirror / Atom feed
* Re: Mutually dependent private types
@ 1998-05-22  0:00 adam
  1998-05-22  0:00 ` John Volan
                   ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: adam @ 1998-05-22  0:00 UTC (permalink / raw)



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




^ permalink raw reply	[flat|nested] 31+ messages in thread
* Mutually dependent private types
@ 1998-05-21  0:00 adam
  1998-05-21  0:00 ` John Volan
  1998-05-21  0:00 ` Matthew Heaney
  0 siblings, 2 replies; 31+ messages in thread
From: adam @ 1998-05-21  0:00 UTC (permalink / raw)



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:

        package P1 is
            type T1 is private;
        private
            type T1_Info;
            type T1 is access T1_Info;
        end P1;

        package P2 is
            type T2 is private;
        private
            type T2_Info;
            type T2 is access T2_Info;
        end P2;

    and this will work since it's legal for P1's package body to
    depend on P2 and P2's package body to depend on P1.  The
    definitions of P1.T1_Info and P2.T2_Info would contain references
    to the other package's type.

(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):

        package P1 is
            type T1 is ...
        end P1;

        package P2 is
            type T2 is ...
        end P2;

        with P2;
        package P1.Operations is
            procedure Some_Operation (X : T1;  Y : P2.T2);
        end P1.Operations;

        with P1;
        package P2.Operations is
            procedure Some_Operation (X : T2;  Y : P1.T1);
        end P2.Operations;

    Actually, you don't have to do this for both packages; you can
    solve the problem by splitting the operations in just one of the
    packages.

(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:

        package P1 is
            type T1 is private;
        private
            type T1_Info;
            type T1 is access T1_Info;
        end P1;

        with P2;
        package P1.Operations is
            procedure Some_Operation (X : T1;  Y : P2.T2);
        end P1.Operations;

    you can't, because the body of Some_Operation cannot do anything
    useful with X, since the definition of T1_Info is not visible to
    it.

I've been trying to come up with some way around this problem; for
example, I thought about putting some routines in the private part of
P1 that P1.Operations could access to give it information about
T1_Info, or by setting up another private child package to declare
actual type info, but I couldn't quite get anything to work.  Does
anyone know of a good way to accomplish this, without using
Unchecked_Conversion?  (It's pretty easy to come up with a solution
using Unchecked_Conversion.)  I might be missing something obvious
here due to my incomplete knowledge of Ada 95.

P.S. I believe this would also be solved by Tucker Taft's "with type"
proposed language extension.

                                -- thanks, Adam


-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading




^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~1998-06-04  0:00 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-05-22  0:00 Mutually dependent private types adam
1998-05-22  0:00 ` John Volan
1998-05-22  0:00 ` Matthew Heaney
1998-05-22  0:00 ` Brian Rogoff
  -- strict thread matches above, loose matches on Subject: below --
1998-05-21  0:00 adam
1998-05-21  0:00 ` John Volan
1998-05-21  0:00 ` Matthew Heaney
1998-05-22  0:00   ` John Volan
1998-05-22  0:00     ` Matthew Heaney
1998-05-26  0:00       ` John Volan
1998-05-26  0:00         ` Matthew Heaney
1998-05-27  0:00           ` John Volan
1998-05-27  0:00             ` Matthew Heaney
1998-05-28  0:00               ` John Volan
1998-05-28  0:00                 ` Matthew Heaney
1998-05-29  0:00                   ` John Volan
1998-05-29  0:00                 ` Brian Rogoff
1998-05-29  0:00                   ` John Volan
1998-05-29  0:00                     ` Brian Rogoff
1998-05-29  0:00                       ` John Volan
1998-05-30  0:00                 ` Geoff Bull
1998-05-30  0:00                   ` Fergus Henderson
1998-06-01  0:00                     ` John Volan
1998-06-02  0:00                       ` Fergus Henderson
1998-06-04  0:00                       ` Robert Dewar
1998-05-26  0:00       ` Robert I. Eachus
1998-05-26  0:00         ` John Volan
1998-05-27  0:00           ` Robert I. Eachus
1998-05-29  0:00             ` John Volan
1998-05-27  0:00           ` Jerry van Dijk
1998-05-29  0:00             ` John Volan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox