Home | Contact | Pricing | News | Events | Partners | Mailing List | Site Map
Gnat Pro. Powerful tools. Frontline Support. Ada expertise.

Gem #1: Limited Types in Ada 2005 — Limited Aggregates

Author: Bob Duff, AdaCore

Abstract: Ada Gem #1 — Ada 2005 allows construction of limited objects via aggregates, thus gaining the advantage of the full coverage rules, which was previously available only for non limited types.

Next Gem » | Gems Menu

Let’s get started…

One of my favorite features of Ada is the “full coverage rules” for aggregates. For example, suppose we have a record type:

   type Person is
      record
         Name : Unbounded_String;
         Age : Years;
      end record;

We can create an object of the type using an aggregate:

   X : constant Person :=
      (Name => To_Unbounded_String (”John Doe”),
       Age => 25);

The full coverage rules say that every component of Person must be accounted for in the aggregate. If we later modify type Person by adding a component:

   type Person is
      record
         Name : Unbounded_String;
         Age : Natural;
         Shoe_Size : Positive;
      end record;

and we forget to modify X accordingly, the compiler will remind us. Case statements also have full coverage rules, which serve a similar purpose.

Of course, we can defeat the full coverage rules by using “others” (usually for array aggregates and case statements, but occasionally useful for record aggregates):

   X : constant Person :=
      (Name => To_Unbounded_String (”John Doe”),
       others => 25);

According to the Ada RM “others” here means precisely the same thing as “Age | Shoe_Size”. But that’s wrong: what “others” really means is “all the other components, including the ones we might add next week or next year”. That means you shouldn’t use “others” unless you’re pretty sure it should apply to all the cases that haven’t been invented yet.

So far, this is old news — the full coverage rules have been aiding maintenance since Ada 83. So what does this have to do with Ada 2005?

Suppose we have a limited type:

   type Limited_Person is limited
      record
         Self : Limited_Person_Access := Limited_Person'Unchecked_Access;
         Name : Unbounded_String;
         Age : Natural;
         Shoe_Size : Positive;
      end record;

This type has a self-reference; it doesn’t make sense to copy objects, because Self would end up pointing to the wrong place. Therefore, we would like to make the type limited, to prevent programmers from accidentally making copies. After all, the type is probably private, so the client programmer might not be aware of the problem. We could also solve that problem with controlled types, but controlled types are expensive, and add unnecessary complexity if not needed.

In Ada 95, aggregates were illegal for limited types. Therefore, we would be faced with a difficult choice: Make the type limited, and initialize it like this:

   X : Limited_Person;
   X.Name := To_Unbounded_String ("John Doe");
   X.Age := 25;

which has the maintenance problem the full coverage rules are supposed to prevent. Or, make the type nonlimited, and gain the benefits of aggregates, but lose the ability to prevent copies.

In Ada 2005, an aggregate is allowed to be limited; we can say:

   X : aliased Limited_Person :=
      (Self => null, – Wrong!

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

We’ll see what to do about that “Self => null” in a future gem.

One very important requirement should be noted: the implementation is required to build the value of X “in place”; it cannot construct the aggregate in a temporary variable and then copy it into X, because that would violate the whole point of limited objects — you can’t copy them

 

Posted by Posted in Ada / Ada 2005, Development Log, Devt log - Gem of the Week

Have your own idea for a Gem?

If you have an idea for a Gem you would like to contribute please feel free to contact us at: gems@adacore.com

Discussion

6 responses to “Gem #1: Limited Types in Ada 2005 — Limited Aggregates”


  1. Paul F. Pearson said:

    “[...]but controlled types are expensive”. I’ve heard this before, and I can believe it. However, has there been any analysis of *how* expensive? What is their cost compared to a custom implementation providing similar functionality (e.g. providing a “deep copy” procedure/function)? How can someone decide when a controlled type is “too expensive”?

    For instance, when should I decide to *not* use Unbounded_String, since (at least in the GNAT versions I’ve seen) it uses a Controlled type?


  2. Franco Gasperoni said:

    “What is the cost of controlled types”, asks Paul.

    The way controlled types are currently implemented in GNAT is to put each controlled object onto a finalization list so that Finalize can be called before the object gets destructed.

    So each controlled object has two extra pointers to be doubly chained. So there is a space cost (for you to decide whether that is acceptable or not).

    The runtime cost is adding/removing each controlled object onto the finalization list and calling initialize/adjust/finalize when appropriate.

    More details are available in a paper that Cyrille, Gary, and I wrote several years ago. The paper is available at:

    http://www.adacore.com/2001/01/26/the-gnat-implementation-of-controlled-types/

    Enjoy :)


  3. Paul F. Pearson said:

    Thank you, Franco.

    That paper is *very* informative (as usual). I can see that there is quite a bit of overhead. While I was hoping to find an analysis quantifying the expense, I can see that my hope was a bit unrealistic.

    I suppose that my design decisions related to controlled types will be made like other features – if my code needs to be fast, be *very* thoughtful about using controlled types.

    Of course, this means that Unbounded_String will be used less often… :-)


  4. Paul F. Pearson said:

    I forgot to comment on the topic:

    This looks to be a *very* useful feature of Ada 2005. Thank you for pointing this out.

    I look forward to the next “gem”.


  5. Bob Duff said:

    Paul F. Pearson said, “Of course, this means that Unbounded_String will be used less often… :-)”

    Yes, Unbounded_String is controlled and is therefore expensive. Whether it’s _too_ expensive can best be determined by measuring.

    Note that my example used Unbounded_String, and then I turn around and say controlled types are expensive. Oh well, it’s just an example.


  6. Paul F. Pearson said:

    Bob Duff said:

    Note that my example used Unbounded_String, and then I turn around and say controlled types are expensive. Oh well, it’s just an example.

    That actually helps answer my question – a feature can be “expensive”, but worth the expense (e.g. a Mercedes vs. a Pinto). In your example, the simplicity of the Unbounded_String helped keep the focus on the subject (in spite of my tangent).

Leave a Reply