Separate declarations of types/packages aliases in

2019-07-19 18:26发布

问题:

I would like to declare some "user-defined compiler-constants" to keep my specification files as "constant" as possible. This is something common in C++, e.g. :

// misc/config.hh
namespace misc
{
  typedef std::shared_ptr<A> A_ptr; 
  namespace arch = ibmpc;
}

// misc/code.hh
#include "misc/config.hh"
namespace misc
{
  void function p(A_ptr a);
}

Which would be in Ada :

-- misc.ads
package Misc is
  use Types; ----> forbidden !

  procedure P(A : A_Access);
end Misc;

-- misc-types.ads
package Misc.Types is
  type A_Access is A'Access;
end Misc.Types;

Of course this does not work since use is a context keyword...hence my question : how is it possible to do something with the same results in Ada ?

回答1:

I think this is a reasonable mapping from your C++ original to Ada:

To start with, corresponding more-or-less, I think, to your namespace misc, in file misc.ads,

package Misc is
end Misc;

Then, corresponding to config.hh, in file misc-config.ads,

package Misc.Config is
   type A is (For_Example, An_Enumeration);
   type A_Access is access A;
end Misc.Config;

(which could, of course, also reference types in Misc). Then, corresponding to code.hh, in file misc-code.ads,

with Misc.Config;
package Misc.Code is
   use Config;
   procedure P (A : A_Access);
end Misc.Code;

Personally I wouldn’t use Config;, at any rate in specs - it can make it difficult to work out where something is defined. Note, you can say use Config; or use Misc.Config; where shown, because you’re in a child of Misc; in the context clause, which is also OK, you would have to use Misc.Config;.



回答2:

Ok, while I see what you're trying to do you're going about it wrong. The problem you have with the given sniplets is this: circular dependency.

Now Ada has a great way of managing circular dependency by making it non-circular (in a sense) through it's use of specs and bodies. As the two are discrete, we can have two sets of spec/body files where the body references the other's spec precisely because the specs are publicly visible.

As an example, admittedly ridiculous; let's use fountain-pens and ink-cartridges.

With Cartridge;
Package Pen is

  Subtype Model_Number is Positive Range 1000..3304;
  Type Fountain_pen is private;
  -- Pen procedures
private
  Type Fountain_pen is Record
 Model  : Model_Number;
     Ink    : Cartridge.Ink_Cartridge;
  end record;      
end Pen;

and

With Pen;
Package Cartridge is
  Type Ink_Cartridge is private;
  -- Ink procedures
private
  Type Ink_Cartridge is record
     Color      : Integer; -- I'm being lazy.
     This_Pen   : Pen.Fountain_pen;
  end record;
end Cartridge;

and

Package Body Pen is
  --- Pen Stuff
end Pen;

Package Body Cartridge is
  -- Ink stuff
end Cartridge;

(Not compiled.) I forget how to create a component of a circularly-nested type though... Anyway, you should get the general idea there. But what you're wanting is fundamentally different than mutually dependent types; what you want is some sort of container for your constants.

I would recommend using child packages. Something like Misc and Misc.Constants; where you place your base-types into Misc, and the constants into Misc.Constants. If your types are dependent on your constants you might make a separate child package for them Misc.Types and use the mutual withing as shown above.



回答3:

You could put the child package spec inside the parent package spec, like this:

package Misc is
   package Types is
      type A is private;
      type A_Access is access A;
      -- other stuff
   end Types;

   procedure P (A : Types.A_Access);
end Misc;

you can even use Types; after the declaration of Misc.Types.



标签: packaging ada