I have been writing a lot of very tedious and unsafe code recently. The code is related to serialization and input-output. The problem is inability to dispatch to lately, when the type is frozen. I cannot go back and redesign the whole types hierarchy or I intentionally do not want to in order to keep the new code separate. Consider an embedded target that has a carefully designed set of types. On the host side you might wish to add pretty printing, graphic rendering and thousands other stuff not needed on the target.
I came up to a relatively simple language extension of the case statement that would select alternatives according to the object’s tag. Let we have a hierarchy of types:
type I is interface;
type T is tagged null record;
type T1 is new T with null record;
type T2 is new T with null record;
type T3 is new T1 and I with null record;
type T4 is new T1 and I with null record;
...
procedure Print (File : File_Type; Object : T'Class);
How to implement Print? Presently one have to write a long if-statement with renaming declarations:
if Object in T1 then
declare
X : T1 renames T1 (Object);
begin
...
end;
elsif Object in I'Class then
...
It is not only excessively long, but also exposed to errors. E.g. checking for T3 must precede checking for I’Class.
The dispatching case statement would be:
case Object is
when X : T1 => -- X is T1 renames T1 (Object)
... -- E.g. Print (X);
when X : I'Class =>
...
when X : T3 =>
...
when T2 | T4 => -- No object declared
...
when T'Class => -- Covers all Object'Tag, no others needed
...
end case;
The expression in the case statement can be either a class-wide object or of the Tag type. In the latter case no object can be specified in the alternatives and others is required.
The rules about the alternatives’ choices:
- No object declaration is allowed in alternatives having a list of choices (so long we have no anonymous tagged types)
- If alternative’s choices lists intersect then they must be strict sub/supersets (nested). In the example above I’Class contains T3 and is inequal to T3.
- Among matching alternatives the alternative corresponding to the most narrow choice is selected (the rule above guarantees its existence)
- When the union of all choices lists does not cover all argument, others is required.