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:

   <b>package</b> P <b>is</b>
      <b>type</b> T (<>) <b>is</b> <b>limited</b> <b>private</b>;
      <b>function</b> Make_T (Name : String) <b>return</b> T; <i>-- constructor function</i>
      <b>type</b> T <b>is</b> <b>new</b> Limited_Controlled <b>with</b>
         <b>end</b> <b>record</b>;
   <b>end</b> P;
   <b>package</b> <b>body</b> P <b>is</b>
      <b>function</b> Make_T (Name : String) <b>return</b> T <b>is</b>
         <b>return</b> (Name => To_Unbounded_String (Name), <b>others</b> => <>);
      <b>end</b> Make_T;
   <b>end</b> P;
   <b>function</b> Make_Rumplestiltskin <b>return</b> T <b>is</b>
       <b>return</b> Make_T (Name => “Rumplestiltskin”);
   <b>end</b> 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:

   <b>procedure</b> 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:

   <b>type</b> T_Ref <b>is</b> <b>access</b> <b>all</b> T;
   Global : T_Ref;
   <b>procedure</b> Heap_Alloc <b>is</b>
      Local : T_Ref;
      Local := <b>new</b> T'(Make_Rumplestiltskin);
      <b>if</b> … <b>then</b>
         Global := Local;
      <b>end</b> <b>if</b>;
   <b>end</b> 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:

   <b>type</b> Outer_Type <b>is</b> <b>limited</b>
         This : T;
         That : T;
      <b>end</b> <b>record</b>;
   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 => ""); <i>-- Illegal!</i>

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; <i>-- Illegal!</i>

Last Updated: 10/26/2017
Posted on: 10/1/2007