Gem #2: Limited Types in Ada 2005 — <> Notation in Aggregates

by Bob Duff —AdaCore

Let's get started…

Last week, we noted that Ada 2005 allows aggregates for limited types. Such an aggregate must be used to initialize some object (which includes parameter passing, where we are initializing the formal parameter). Limited aggregates are “built in place” in the object being initialized.

Here's the example:

   type Limited_Person is limited
         Self : Limited_Person_Access := Limited_Person'Unchecked_Access;
         Name : Unbounded_String;
         Age : Natural;
         Shoe_Size : Positive;
      end record;
   X : aliased Limited_Person :=
      (Self => null, – Wrong!

       Name => To_Unbounded_String (”John Doe”),
       Age => 25,
       Shoe_Size => 10);
   X.Self := X'Access;

It seems uncomfortable to set the value of Self to the wrong value (null) and then correct it. It also seems annoying that we have a (correct) default value for Self, but in Ada 95, we can't use defaults with aggregates. Ada 2005 adds a new syntax in aggregates — “<>” means “use the default value, if any”.

Here, we can say:

   X : aliased Limited_Person :=
      (Self => <>,
       Name => To_Unbounded_String (”John Doe”),
       Age => 25,
       Shoe_Size => 10);

The “Self => <>” means use the default value of Limited_Person'Unchecked_Access. Since Limited_Person appears inside the type declaration, it refers to the “current instance” of the type, which in this case is X. Thus, we are setting X.Self to be X'Unchecked_Access.

Note that using “<>” in an aggregate can be dangerous, because it can leave some components uninitialized. “<>” means “use the default value”. If the type of a component is scalar, and there is no record-component default, then there is no default value.

For example, if we have an aggregate of type String, like this:

    Uninitialized_String_Const : constant String := (1..10 => <>);

we end up with a 10-character string all of whose characters are invalid values. Note that this is no more nor less dangerous than this:

    Uninitialized_String_Var : String (1..10); – no initialization

    Uninitialized_String_Const : constant String := Uninitialized_String_Var;

As always, one must be careful about uninitialized scalar objects.