comp.lang.ada
 help / color / mirror / Atom feed
From: John Volan <johnv@ac3i.dseg.ti.com>
Subject: Re: Mutually dependent private types
Date: 1998/05/29
Date: 1998-05-29T00:00:00+00:00	[thread overview]
Message-ID: <356F2910.E3BD7C4F@ac3i.dseg.ti.com> (raw)
In-Reply-To: m34syanhcg.fsf@mheaney.ni.net


Matthew Heaney wrote:
> 
> The pragma idea is more or less equivalent to "with P.T".
> 
> Thinking about it more, you could name it thusly:
> 
> with P;
> pragma Elaborate_None (P);
> package Q is ...;
> 
> So the answer to your question is that the spec for P is not elaborated
> prior to its use (with certain constraints) by Q.

Hmm... I'm not sure a pragma per se is the ultimate solution, but
there's something interesting implied by your suggestion: Let the
compiler do the work.

Here's what I mean: So far, all the proposals for language extensions
have placed the burden on the programmer to decide when and how to
resolve a circular spec dependency.  Tucker's "with type" clause, my
"package abstracts", and Norman Cohen's "package parts" all require the
programmer to decide that forward declarations are needed, and then to
write those forward declarations in a separate place apart from the
corresponding full declarations. (Yes, even Tucker's "with type" forces
you into that, in a way. See footnote (*).)  That seemed to be in
keeping with Ada's language design principles, because Ada already
forces you to write interfaces and implementations in separate places
(specs and bodies).  However, I can understand how having to pull out
forward declarations can be something of an annoyance.  (I'm sure the
typical Eiffel or Java programmer would find it annoying to have to pull
specs and bodies apart, too... :-)

But another common element in these proposals is that they all basically
boil down to finding a way to weaken the impact of the conventional
with-clause.  Well, why not just introduce a relaxed form of "with", and
leave it at that? Such a clause should provide pretty much the same
level of visibility to the contents of a package spec as the
conventional with-clause does, but only in a "forward" manner that does
not imply an elaboration-order dependency.  Make it the compiler's job
to determine what you can legally use out of the package spec when you
import it with such a relaxed with-clause; don't require the author of
that spec to pull the forward declarations out.  Some care would need to
be taken to come up with a good set of rules to put into the RM; they'd
probably be comparable in complexity to the "freezing" rules.
Compiler-writers would have to be careful to properly enforce those
rules, but that's what compilers are for.

One element that I think would need to be retained from the "with type"
and "package abstract" proposals: If you use this relaxed form of
with-clause to get "forward" visibility to a package spec, you should be
forced to use the conventional with-clause to get "full" visibility,
before being allowed to do things that would require elaboration of the
package (for example, creating an instance of a type or invoking a
subprogram).

For that reason, I'm not sure a pragma is enough, I think you need some
way to syntactically distinguish the relaxed vs. strong forms of
"with".   How about this: Adopt my "with abstract" clause, but without
the "package abstract" construct.  Just leave the package abstract as
something implied, something the compiler could derive for itself from
the package spec.  (If you don't like my recycling of the "abstract"
keyword, come up with some other syntax.)

For example:

with abstract Patients; -- does not force elaboration
with Sets;
package Doctors is
  type Doctor_Type is tagged limited private;
  type Doctor_Access_Type is access all Doctor_Type'Class;
  package Doctor_Sets is
    new Sets (Element_Type => Doctor_Access_Type);
  procedure Treat_Patient
    (Doctor  : in out Doctor_Type;
     Patient : in out Patients.Patient_Type'Class);
    -- okay "forward" usage of Patient_Type,
    -- because type is pass-by-reference
  procedure Bill_Patient
    (Doctor  : in out Doctor_Type;
     Patient : in out Patients.Patient_Type'Class);
  procedure Add_Regular_Patient
    (Doctor  : in out Doctor_Type;
     Patient : in     Patients.Patient_Access_Type);
    -- okay "forward" usage of Patient_Access_Type,
    -- even though pass-by-value, because type-size is
    -- statically determined without need for elaboration
  function Get_Regular_Patients
    (Doctor : in Doctor_Type)
     return Patients.Patient_Sets.Set_Type;
    -- Here's where things get dicey: Would this 
    -- be an okay "forward" usage of a generic
    -- instantiation?
  ...
end Doctors;

with abstract Doctors; -- does not force elaboration
with Sets;
package Patients is
  type Patient_Type is tagged limited private;
  type Patient_Access_Type is access all Patient_Type'Class;
  package Patient_Sets is
    new Sets (Element_Type => Patient_Access_Type);
  procedure Visit_Doctor
    (Patient : in out Patient_Type;
     Doctor  : in out Doctors.Doctor_Type'Class);
     -- okay "forward" usage of Doctor_Type, 
     -- because type is pass-by-reference
  procedure Pay_Doctor
    (Patient : in out Patient_Type;
     Doctor  : in out Doctors.Doctor_Type'Class);
  procedure Set_Family_Doctor
    (Patient : in out Patient_Type;
     Doctor  : in     Doctors.Doctor_Access_Type);
    -- okay "forward" usage of Doctor_Access_Type,
    -- even though pass-by-value, because type-size is
    -- statically determined without need for elaboration
  function Get_Family_Doctor
    (Patient : in Patient_Type)
     return Doctors.Doctor_Access_Type;
  ...
end Patients;

with Patients; -- forces elaboration
package body Doctors is
  procedure Bill_Patient
    (Doctor  : in out Doctor_Type;
     Patient : in out Patients.Patient_Type'Class) is
  begin
    ...
    Patients.Pay_Doctor (Patient, Doctor);
    -- requires fully-elaborated access to Patients
  end Bill_Patient;
  ...
end Doctors;

with Doctors; -- forces elaboration
package body Patients is
  procedure Visit_Doctor
    (Patient : in out Patient_Type;
     Doctor  : in out Doctors.Doctor_Type'Class) is
  begin
    ...
    Doctors.Treat_Patient (Doctor, Patient);
    -- requires fully-elaborated access to Doctors
  end Visit_Doctor;
  ...
end Patients;

One problem with this: It only works at the library level. What if the
two packages involved are nested inside another package?  There doesn't
seem to be anything analogous you could do.  In my FAQ, I felt it was
important that any solution that could work with library-level packages
should also work with nested packages.  I demonstrated how my package
abstracts could work even in a nested context, and I also showed that
Tucker's proposal could also work, if you generalize his "with type"
idea to include something I called a "forward incomplete type
declaration."

(*) Footnote: I claim that even Tucker's "with type" clause forces you
to pull forward declarations out of a spec.  At first glance, you might
not think so. However, one of the difficulties people have had with
Tucker's proposal is that it only gives you forward visibility to a
single type. For example:

with type Doctors.Doctor_Type;

would give you forward visibility to the tagged type Doctor_Type (and
its classwide type Doctor_Type'Class), but not to an auxiliary type like
Doctor_Access_Type, or an ADT like Doctor_Sets instantiated off of that
auxiliary type. Such auxiliary declarations might "belong" in the
Doctors package, but to make them available without a full "with
Doctors;" clause, you have to pull them out into another package:

with type Doctors.Doctor_Type;
with Sets;
package Doctors_Access is
  type Doctor_Access_Type is access all Doctors.Doctor_Type'Class;
  package Doctor_Sets is 
    new Sets (Element_Type => Doctor_Access_Type);
end Doctors_Access;

-- 
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. :-)" );




  reply	other threads:[~1998-05-29  0:00 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-05-21  0:00 Mutually dependent private types adam
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       ` Robert I. Eachus
1998-05-26  0:00         ` John Volan
1998-05-27  0:00           ` Jerry van Dijk
1998-05-29  0:00             ` John Volan
1998-05-27  0:00           ` Robert I. Eachus
1998-05-29  0:00             ` John Volan
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 [this message]
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-21  0:00 ` John Volan
  -- strict thread matches above, loose matches on Subject: below --
1998-05-22  0:00 adam
1998-05-22  0:00 ` John Volan
1998-05-22  0:00 ` Brian Rogoff
1998-05-22  0:00 ` Matthew Heaney
replies disabled

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