Section 12.2 - Simple Uses of Access Variables

Let's imagine that we want to create a binary tree of Unbounded_Strings. A binary tree is a set of nodes; each node has a way to locate its parent, its left child node, and a right child node. Each node also has data it contains (an Unbounded_String). Defining a record for a binary tree node using access values is easy:

  type Tree_Node is
    record
      Parent      : Tree_Access;
      Left, Right : Tree_Access;
      Data        : Unbounded_String;
    end record;

Of course, defining Tree_Node depends on a type called Tree_Access, which depends on a type called Tree_Node. Note the circularity - each type's definition depends on the other. The way to solve this is to use an ``incomplete type declaration'' of the record (this is the same thing you'd do in C or Pascal). An incomplete type declaration has the keyword "type", the name of the type that you plan to declare later, and an immediately following semicolon. For example, before defining Tree_Node you'd do the following:

  type Tree_Node; -- Incomplete type declaration.
  type Tree_Access is access Tree_Node;

You can then declare variables of access types using the normal variable declaration syntax, for example, you can create two access variables this way:

  Current, Root : Tree_Access;

What we need is an operation that will create a new Tree_Node object (in a general storage area) and then return an access value referencing this newly-created object. The process of creating a new object this way is called allocation In C the allocation operation is called "malloc", while in Pascal and C++ it's called "new". Ada also calls this operation new, and Ada has the same syntax as C++ and Pascal; the keyword new is followed by the name of the type to be created. For example, here's how to create a new object of type Tree_Node, setting the value of "Current" to access it:

  Current := new Tree_Node;

Once an access value references a real object (instead of being null), you can use the ``dot'' operation to refer to the object pointed to by the access value. This is the same syntax as when accessing values in a record. For example, here's how to set the data value of the Node being pointed to by Current:

  Current.Data := To_Unbounded_String("Hello!");

In some cases you want to work with the "entire" object being accessed instead of a piece of it. For example, let's say that you have some procedure (My_Procedure) that requires as input a Tree_Node. You can't just pass in an access value to a Tree_Node, because the types are different (an access value is different than what it accesses). To handle this, simply use the word "all" after the dot operation to refer to the entire object:

  My_Procedure(Current.all);

Finally, you can have multiple different pointers referring to the same object. This is called access assignment; all you need to do is use ordinary assignment statements. For example, to set the access value "Root" so that it references the same node as "Current", simply do:

  Root := Current;


Quiz:


If you execute the statements listed above, what is the value of Root.Data?
  1. An empty string.
  2. "Hello!"
  3. None; an exception would be raised.

You may also:

PREVIOUS Go back to the previous section

NEXT     Skip to the next section

OUTLINE  Go up to the outline of lesson 12

David A. Wheeler (wheeler@ida.org)