Reputation: 53
my question is very simple. I have 2 generic package. I use each package 2 times (once for integers and strings for once). I have a "main" file that use the package selected by the user. - package1 with integer - or package1 with string - or package2 with integer - or package2 with string
procedure main is
package aB is new package1(integer, false, afficheInteger, true);
--package aB is new package1(Unbounded_String, true, afficheUnbounded, true);
--package aB is new package2(1,integer, false, afficheInteger, true);
--package aB is new package2(1, Unbounded_String, true, afficheUnbounded, true);
begin aB.init(); .....
The goal is to use the same code (main) for the 4 packages.
Unfortunately I can't find how to do this properly. For the moment I put the list of packages and I comment the packages i don't use. Is it possible to make pseudo if in the begin or init the package in the begin ? Maybe with a package parameter in the main function ?
Thanks a lot and sorry for my english !
Update :
Is it possible to pass a package parameter in a function ? Like this :
procedure init_paquetage1_int is
package aB is new packA(integer, false, afficheInteger, true);
begin
main(aB);
end init_paquetage1_int;
procedure main(aB : packA) is
begin
aB.init();
....
end main;
It's not working.
Upvotes: 2
Views: 1884
Reputation: 44804
OK. First off, I don't see any way you could hope for this to work, unless the routines you are calling in the package(s) have the same parameter profile regardless of which type was used. Typically a generic package will have at least one routine that uses one of the types you instantiated it with in the routine's parameters (or as a return type).
If the routines you want to use do in fact have identical profiles, I can think of a couple of things you could do. The first is to use a pointer to the routine you want to call, and pass that in.
type Init_Routine is access procedure ();
begin
main (ab.Init'access);
The second would be to make your generic packages all contain tagged types derived from a common parent abstract
tagged type that has the routines you want to call defined as abstract
routines in the parent. If you do that, you can use dynamic dispatch to select between them at runtime.
package Parent is
type Instance is abstract tagged null record;
type Dispatching_Instance_Ptr is access all Instance;
procedure Init (I : in out Instance) is abstract;
end Parent;
generic
--// Whatever your generic parameters are...
Package1 is
type Instance is new Parent.Instance with null record;
procedure Init (I : in out Instance);
...
end Package1;
--// (Package2 looks similar)
Skipping down to the calling code:
Choice : Parent.Dispatching_Instance_Ptr;
begin
--// Let's assume the user "chooses" package aB
Choice := new'aB.Instance;
main (Choice);
...and for main:
procedure main(xx : in Parent.Dispatching_Instance_Ptr) is
begin
Parent.Init(xx.all); --// This should dynamic dispatch to the proper init routine
....
end main;
Note: I haven't run this through a compiler, so there are probably minor issues. I've found and fixed a couple already.
Upvotes: 6
Reputation: 240
Each time you instantiate a generic package, it is treated as a separate package. Therefore, you need to use a different package name for each instantiation.
procedure main is
package aA is new package1(integer, false, afficheInteger, true);
package aB is new package1(Unbounded_String, true, afficheUnbounded, true);
package aC is new package2(1,integer, false, afficheInteger, true);
package aD is new package2(1, Unbounded_String, true, afficheUnbounded, true);
...
You can now use each of these as a separate package.
aA.init();
aB.init();
...
You can pass in procedures as parameters, but not packages.
If you're still confused on generics, I suggest you read http://en.wikibooks.org/wiki/Ada_Programming/Generics
Upvotes: 2