Reputation: 27
I'm writing a generic library. I have a protected object that needs to be accessed by code in two packages. Both the package containing the object, and the packages that need to access it, are generic. I'll call the packages Main_Pkg
, Second_Pkg
and Object_Pkg
for clarity. All three packages are instantiated with the same type.
With non-generic code, I would simply 'with' Object_Pkg
in Main_Pkg
and Second_Pkg
. I understand that I can't do this with generic packages, since Object_Pkg
won't be instantiated.
So far, I've tried having Main_Pkg
create an instance of Object_Pkg
package Instance_Of_Object_Pkg is new Object_Pkg(Custom_Type)
and having Second_Pkg
access it using code like
Main_Pkg.Instance_Of_Object_Pkg.Object.Procedure
but I get a compiler error
invalid prefix in selected component "Main_Pkg"
This is my first time working with generic types, so I'm not sure what's causing the problem or what to try next. Is it possible to do this at all, and if so how?
Upvotes: 1
Views: 975
Reputation: 31699
If Main_Pkg and Second_Pkg are closely enough related that you're going to have one of those packages accessing something defined in the other package, then perhaps making them totally separate generic packages isn't the right way to organize them. Consider making them both children of some other package.
It sounds like you have something like
generic
type T is private;
package Main_Pkg is ... end Main_Pkg;
generic
type T is private;
package Second_Pkg is ... end Second_Pkg;
Note that this doesn't set up a rule that Main_Pkg and Second_Pkg have to be instantiated with the same type for T. If your program says something like
package Main_Inst is new Main_Pkg (T => T1);
package Second_Inst is new Second_Pkg (T => T2); -- some different type
then obviously Second_Inst and Main_Inst couldn't really communicate with each other (using the generic type T). Instantiating them with the same type doesn't magically cause a connection between the two instantiations where no connection existed before.
So there has to be some connection between the two generics. Generic formal packages are one possibility, the way Simon presented it. Another possibility is for Second_Pkg to have a generic formal package parameter that's an instance of Main_Pkg:
generic
with package With_Main_Pkg is new Main_Pkg (<>);
package Second_Pkg is ...
and now Second_Pkg could refer to With_Main_Pkg (and it could use With_Main_Pkg.T
to get Main_Pkg's formal type).
But it might be simplest to put Main_Pkg and Second_Pkg in some larger package, and have T be a parameter to that larger package instead of Main_Pkg and Second_Pkg.
generic
type T is private;
package Larger_Pkg is
package Object_Inst is new Object_Pkg (T);
-- this might belong in Larger_Pkg's body, instead of the specification.
-- The bodies of Main_Pkg and Second_Pkg would both have it available.
package Main_Pkg is ...
package Second_Pkg is ...
end Larger_Pkg;
Maybe Main_Pkg and Second_Pkg need to be generic also, if they need some other generic parameters besides T; I don't know. This solution doesn't let you put the specifications of Main_Pkg and Second_Pkg in separate units; you have to nest them in Larger_Pkg. But you can still make the bodies separate by using separate compilation (package body Main_Pkg is separate;
). And if Main_Pkg and Second_Pkg can be generics, you can make them child units:
generic
package Larger_Pkg.Main_Pkg is ...
end Larger_Pkg.Main_Pkg;
but then Object_Inst can't be in the body of Larger_Pkg. It could be in the private part, though.
Anyway, the best answer depends in part on what concepts these packages are supposed to represent in your real program.
Upvotes: 0
Reputation: 25501
I think you may be able to use a generic formal package.
Not bothering with the protected object (being able to access anything should demonstrate the point) something like
generic
type T is private;
package Object_Pkg is
Arr : array (1 .. 10) of T;
end Object_Pkg;
and then specify that Main_Pkg
is to be instantiated with a type T
and an instantiation of Object_Pkg
with the same type, like this:
with Object_Pkg;
generic
type T is private;
with package Inst is new Object_Pkg (T);
package Main_Pkg is
Obj : T := Inst.Arr (1);
end Main_Pkg;
Now, first instantiate Object_Pkg
:
with Object_Pkg;
package Object_Inst is new Object_Pkg (T => Integer);
and then instantiate Main_Pkg
with the same type and the new instance of Object_Pkg
:
with Object_Inst;
with Main_Pkg;
package Main_Inst is new Main_Pkg (T => Integer,
Inst => Object_Inst);
Upvotes: 3