Reputation: 603
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
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
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
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