Gem #11: Limited Types in Ada 2005 — Constructor Functions Part 2
by Bob Duff —AdaCore
Let's get started…
We've earlier seen examples of constructor functions for limited types similar to this:
package P is
type T (<>) is limited private;
function Make_T (Name : String) return T; -- constructor function
private
type T is new Limited_Controlled with
record
…
end record;
end P;
package body P is
function Make_T (Name : String) return T is
begin
return (Name => To_Unbounded_String (Name), others => <>);
end Make_T;
end P;
function Make_Rumplestiltskin return T is
begin
return Make_T (Name => “Rumplestiltskin”);
end Make_Rumplestiltskin;
It is useful to consider the various contexts in which these functions may be called. We've already seen things like:
Rumplestiltskin_Is_My_Name : T := Make_Rumplestiltskin;
in which case the limited object is built directly in a standalone object. This object will be finalized whenever the surrounding scope is left.
We can also do:
procedure Do_Something (X : T);
Do_Something (X => Make_Rumplestiltskin);
Here, the result of the function is built directly in the formal parameter X of Do_Something. X will be finalized as soon as we return from Do_Something.
We can allocate initialized objects on the heap:
type T_Ref is access all T;
Global : T_Ref;
procedure Heap_Alloc is
Local : T_Ref;
begin
Local := new T'(Make_Rumplestiltskin);
if … then
Global := Local;
end if;
end Heap_Alloc;
The result of the function is built directly in the heap-allocated object, which will be finalized when the scope of T_Ref is left (long after Heap_Alloc returns).
We can create another limited type with a component of type T, and use an aggregate:
type Outer_Type is limited
record
This : T;
That : T;
end record;
Outer_Obj : Outer_Type := (This => Make_Rumplestiltskin,
That => Make_T (Name => “”));
As usual, the function results are built in place, directly in Outer_Obj.This and Outer_Obj.That, with no copying involved.
The one case where we _cannot_ call such constructor functions is in an assignment statement:
Rumplestiltskin_Is_My_Name := Make_T(Name => ""); -- Illegal!
which is illegal because assignment statements involve copying. Likewise, we can't copy a limited object into some other object:
Other : T := Rumplestiltskin_Is_My_Name; -- Illegal!