Stephen Mitchell
Stephen Mitchell

Reputation: 27

Is it possible to access an instance of a generic package from two other generic packages?

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

Answers (2)

ajb
ajb

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

Simon Wright
Simon Wright

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

Related Questions