I encountered the use of predefined class wide access types as the main parameter to a subprogram many times in our code base and would like to know whether it's a flaw in the design or if it has some purpose. Let me first explain what I encountered and what I would like to change:
Let's say I have some tagged type A with a child B extending A:
Package A_Types:
type A is tagged null record;
function Get_Name (This : A) return String
is ("A");
Package B_Types:
type B is new A with null record;
function Get_Name (This : B) return String
is ("B");
Now let's say I'm writing some utility package with a function Show_Name that uses a class wide access:
Package Utilities:
procedure Print_Name (Instance : access A'Class) is
begin
Putline ("Name: " & Instance.Get_Name);
end Print_Name;
This will dispatch Get_Name to the right type of Instance.
However, what I often encounter in our code base is that they define this utility package as:
procedure Print_Name (Instance : A_Cwa) is
begin
Putline ("Name: " & Instance.Get_Name);
end Print_Name;
With A_Cwa defined in the A_Types package as:
type A_Cwa is access all A'Class;
This can of course be called on some instance that's stored somewhere as A_Cwa, but the moment I want to call this procedure on some access to a type in A'Class, it requires me to first make a view conversion to A_Cwa before I can call the procedure on it.
Now, in many places we're calling some procedure on an A_Cwa instance. This would look something like:
Show_Info (Some_Store.Get_The_Instance);
with Show_Info defined in the A_Types package as:
procedure Show_Info (Instance : A_Cwa) is
begin
Utilities.Print_Name (Instance);
end Show_Info;
Since Show_Info is defined in the A_Types package and it seems to do something that looks primitive to the A'Class types, I'd like to write:
Some_Store.Get_The_Instance.Show_Info;
But to make it a primitive I have to change Show_Info into:
procedure Show_Info (This : access A) is
begin
Utilities.Print_Name (A_Cwa (This));
end Show_Info;
I don't like the view conversion here, so to fix this I can change Print_Name into:
procedure Print_Name (Instance : access A'Class) is
begin
Putline ("Name: " & Instance.Get_Name);
end Print_Name;
This works, so it makes me wonder: why use the predefined class wide access type A_Cwa as a parameter in the first place? It seems to prevent the use of the utility procedure on any instance of A unless it's stored as an A_Cwa type.
Was the initial design wrong, or is there a good reason why to use the A_Cwa type instead of the anonymous access A'Class in the signature of the Print_Name utility?
Disclaimer: code in this question was not tested, but analog to what I encountered in our code base. This question is more about the design than it's about fixing some bug.