Ada 95 Quality and Style Guide Chapter 5

Chapter 5: Programming Practices - TOC - 5.4 DATA STRUCTURES

5.4.6 Aliased Objects

guideline

  • Minimize the use of aliased variables.
  • Use aliasing for statically created, ragged arrays (Rationale 1995, §3.7.1).
  • Use aliasing to refer to part of a data structure when you want to hide the internal connections and bookkeeping information.

  • example
    package Message_Services is
       type Message_Code_Type is range 0 .. 100;
       subtype Message is String;
       function Get_Message (Message_Code: Message_Code_Type)
         return Message;
       pragma Inline (Get_Message);
    end Message_Services;
    package body Message_Services is
       type Message_Handle is access constant Message;
       Message_0 : aliased constant Message := "OK";
       Message_1 : aliased constant Message := "Up";
       Message_2 : aliased constant Message := "Shutdown";
       Message_3 : aliased constant Message := "Shutup";
       . . .
       type Message_Table_Type is array (Message_Code_Type) of Message_Handle;
       
       Message_Table : Message_Table_Type :=
         (0 => Message_0'Access,
          1 => Message_1'Access,
          2 => Message_2'Access,
          3 => Message_3'Access,
          -- etc.
         );
       function Get_Message (Message_Code : Message_Code_Type)
         return Message is
       begin
          return Message_Table (Message_Code).all;
       end Get_Message;
    end Message_Services;
    

    The following code fragment shows a use of aliased objects, using the attribute 'Access to implement a generic component that manages hashed collections of objects:

    generic
       type Hash_Index is mod <>;
       type Object is tagged private;
       type Handle is access all Object;
       with function Hash (The_Object : in Object) return Hash_Index;
    package Collection is
       function Insert (Object : in Collection.Object) return Collection.Handle;
       function Find (Object : in Collection.Object) return Collection.Handle;
       Object_Not_Found : exception;
    
       ...
    private
       type Cell;
       type Access_Cell is access Cell;
    end Collection;
    package body Collection is
       type Cell is
       record
          Value : aliased Collection.Object;
          Link  : Access_Cell;
       end record;
       type Table_Type is array (Hash_Index) of Access_Cell;
    
       Table : Table_Type;
       -- Go through the collision chain and return an access to the useful data.
       function Find (Object : in Collection.Object;
                      Index  : in Hash_Index) return Handle is
          Current : Access_Cell := Table (Index);
       begin
          while Current /= null loop
             if Current.Value = Object then
                return Current.Value'Access;
             else
                Current := Current.Link;
             end if;
          end loop;
          raise Object_Not_Found;
       end Find;
       -- The exported one
       function Find (Object : in Collection.Object) return Collection.Handle is
          Index : constant Hash_Index := Hash (Object);
       begin
          return Find (Object, Index);
       end Find;
       ...
    end Collection;
    

    rationale

    Aliasing allows the programmer to have indirect access to declared objects. Because you can update aliased objects through more than one path, you must exercise caution to avoid unintended updates. When you restrict the aliased objects to being constant, you avoid having the object unintentionally modified. In the example above, the individual message objects are aliased constant message strings so their values cannot be changed. The ragged array is then initialized with references to each of these constant strings.

    Aliasing allows you to manipulate objects using indirection while avoiding dynamic allocation. For example, you can insert an object onto a linked list without dynamically allocating the space for that object (Rationale 1995, §3.7.1).

    Another use of aliasing is in a linked data structure in which you try to hide the enclosing container. This is essentially the inverse of a self-referential data structure (see Guideline 5.4.7). If a package manages some data using a linked data structure, you may only want to export access values that denote the "useful" data. You can use an access-to-object to return an access to the useful data, excluding the pointers used to chain objects.


    < Previous Page Search Contents Index Next Page >
    1 2 3 4 5 6 7 8 9 10 11
    TOC TOC TOC TOC TOC TOC TOC TOC TOC TOC TOC
    Appendix References Bibliography