In Ada 95, functions with controlling results are inherited (even if overriding is required), allowing their use with dynamic binding and class-wide types. In most other OOPs, constructors can only be called if you know at compile time the "tag" (or equivalent) of the result you want. In Ada 95, you can use the tag determined by the context to control dispatching to a function with a controlling result. For example:
type Set is abstract tagged private;
function Empty return Set is abstract;
function Unit_Set(Element : Element_Type) return Set is abstract;
procedure Remove(S : in out Set; Element : out Element_Type) is abstract;
function Union(Left, Right : Set) return Set is abstract;
...
procedure Convert(Source : Set'Class; Target : out Set'Class) is
-- class-wide "convert" routine, can convert one representation
-- of a set into another, so long as both set types are
-- derived from "Set," either directly or indirectly.
-- Algorithm: Initialize Target to the empty set, and then
-- copy all elements from Source set to Target set.
Copy_Of_Source : Set'Class := Source;
Element : Element_Type;
begin
Target := Empty; -- Dispatching for Empty determined by Target'Tag.
while Copy_Of_Source /= Empty loop
-- Dispatching for Empty based on Copy_Of_Source'Tag
Remove_Element(Copy_Of_Source, Element);
Target := Union(Target, Unit_Set(Element));
-- Dispatching for Unit_Set based on Target'Tag
end loop;
end Convert;
The functions Unit_Set and Empty are essentially "constructors" and hence must be overridden in every extension of the abstract type Set. However, these operations can still be called with a class-wide expected type, and the controlling tag for the function calls will be determined at run-time by the context, analogous to the kind of (compile-time) overload resolution that uses context to disambiguate enumeration literals and aggregates.
(Tucker Taft) |