Patrick Kelly
Patrick Kelly

Reputation: 603

Ada Generic Package Extension

I have a generic package Containers.Stacks which looks roughly like

generic
    type Value_Type is private;
package Containers.Stacks with Preelaborate is

    --Node stuff

    type Stack is new Container with private;

    --Other Stack stuff
    --Private stuff
end Containers.Stacks;

Everything about is (seems) to work just fine. I would like to reuse this implementation to create an extended but more narrow purpose stack. I have come up with the following:

with Containers.Stacks;

generic
    type Value_Type is range <>;
package Containers.Integer_Stacks with Preelaborate is

    package Stacks is new Containers.Stacks(Value_Type);
    use Stacks;

    type Stack is new Stacks.Stack with null record;

    procedure Add(Self : in out Stack);

    procedure Subtract(Self : in out Stack);

    --So on

end Containers.Integer_Stacks;

The point being, that I don't want to have to reimplement all the common Stack stuff, just for the specific integer stack. This works, but leaves an ugly and odd mess of Containers.Integer_Stacks.Stack and Containers.Integer_Stacks.Stacks.Stack, which I'd like to avoid. Trying to place the package initialization in the private section, however, also hides all the subroutines. Is there a more appropriate way to accomplish what I am trying to do, or do users have to deal with the sibling package initialization being present?

Alternative Approach: I've found it's possible to define a child package of Containers.Stacks called Containers.Stacks.Integer like so:

generic
    with function "+"(Left, Right: Value_type) return Value_Type is <>;
package Containers.Stacks.Integer is
    procedure Add(Self : in out Stack);
end Containers.Stacks.Integer;

And this works. Except that now I can't call Stack.Add, I am forced to call Add(Stack).

Upvotes: 3

Views: 400

Answers (3)

Patrick Kelly
Patrick Kelly

Reputation: 603

The other proposed answers have been great for various reasons, but I'm considering it too important to automatically expose the subroutines of the base container type in the sibling. As such, the best answer was my initial implementation. Hopefully other developers will find the other answers helpful.

Upvotes: 0

Jacob Sparre Andersen
Jacob Sparre Andersen

Reputation: 6601

Your idea for a solution is not giving you a more narrow type, but rather one with more operations.

If you want a more narrow type, where you happen to use the existing type internally, you can do it like this (untested source):

private with Containers_Stack;

generic
   type Value_Type is range <>;
package Containers.Integer_Stack
  with Preelaborate
is
   type Instance is tagged private with null record;

   procedure Add (Item : in out Instance);
   procedure Subtract (Item : in out Instance);
private
   package Internal_Stack is new Containers.Stacks (Value_Type);

   type Instance is tagged private with
      record;
         Data : Internal_Stack.Stack;
      end record;
end Containers.Integer_Stack;

This way clients of Containers.Integer_Stack can only use exactly the operations you explicitly have listed in the package specification.

Upvotes: 2

Simon Wright
Simon Wright

Reputation: 25491

You could look at

with Containers.Stacks;
generic
   type Value_Type is range <>;
   with package Basis_Stack is new Containers.Stacks (Value_Type => Value_Type);
package Containers.Integer_Stacks with Preelaborate is
   type Stack is new Basis_Stack.Stack with private;
...

This does require your user to instantiate Containers.Stacks appropriately themselves.

Upvotes: 4

Related Questions