Abstract Data Types (ADT)


In any programming language, there are several data types that are available for programmers to use, such as integers, floating point numbers, strings or characters. Many applications need more complicated structures of data that can be added on a program-to-program basis; hence, the notion of data abstraction.

A data type consists of a set of values or elements, called its domain, and a set of operators acting on that domain. The domain may be defined either by enumeration, if finite, or by specifying a rule describing its elements.

Once the domain is defined, we need to specify the operations. Two steps are involved here. First, we enumerate operators names, identifying what type of values they both operate on and also return. This step is referred to as prescribing the syntax. Second, we need to describe the operators' functionality, or semantics. There are several ways to give semantics:

Textual description is an informal way of presenting an ADT. Due to natural language ambiguities, it is neither precise nor preferred in discussing ADT.

On the other hand, operational specification gives a description of the ADT at hand in terms of another, primitive type with well-defined mathematical properties. For example, we may describe the ADT set in terms of sequences, which is in this case a well-defined type. In what follows, we concentrate on algebriac specification.


Algebraic Specification

In giving the algebraic specification of some ADT, the process is divided into two parts: syntax and semantics. The syntax description is often referred to as the signature of the algebra, and each "auxiliary" data type used to give this signature is called a sort. Concepts will be illustrated via an ADT we will call STACK.

We have, for the moment, a general intuitive idea about what we mean by a STACK and what kinds of operations are needed in applications for this data type. These operations are: push, pop, top, empty, and newstack.

The syntax gives a description of each one of these operations in the same way we normally describe functions: take some elements from a domain and map them to some element of a domain.

For example, syntax for STACK may be given as follows:

  newstack:                 ------->  STACK

  push    : STACK x INTEGER --------> STACK

  pop     : STACK           --------> STACK

  top     : STACK           --------> INTEGER U 
                                      {undefined}

  empty   : STACK           --------> BOOLEAN

NOTES:

  1. INTEGER and BOOLEAN are the types of this algebra.
  2. The intended meaning for these operators are as follows:
  3. At this stage, implementation is not considered.

Until now, we had only an intuitive idea about the domain of the type STACK. Using the above operators, we may give a precise description of STACK. Among these operators, we identify the least number necessary to construct all possible STACKs. These operators are called constructors for the type.

For our type STACK, we can see that the operators newstack and push are the constructors for STACK. In other words, any element of a STACK type can be built using only operations consisting of newstack and push. Now we have a precise way to describe the domain of the type STACK.


In semantics, we describe the meaning of the operators in terms of how they interact with one another. That will give rise to a set of equations referred to as the axia. For example, axia for STACK may be given as follows:
  1. pop(newstack) = newstack
  2. pop(push(S,I)) = S
  3. top(newstack) = undefined
  4. top(push(S,I)) = I
  5. empty(newstack) = true
  6. empty(push(S,I))= false
NOTES:
  1. S is an arbitrary element of type STACK, and I is an INTEGER.
  2. At this stage, questions concerning implementation are not an issue. All we need at this stage is a desciption of operators, and how they interact with each other.
  3. The domain of STACK can be described in terms of constructors (newstack and push), by means of what may be called the normal lemma of the type STACK, as follows:

    For every STACK S, either:
    a) S = newstack or,
    b) there exists some S1 and I such that S = push(S1,I).


Developing Algebraic Axia

In this section, we give a systematic way to develop our set of "sufficiantly complete" axia. We will use the example of the data type SET.

To create our axia, we must:

  1. Determine Functionality
  2. Write Signatures
  3. Choose Constructors
  4. Write Axia

What we have at the moment is a general notion about the type SET, a collection of some elements -- integers, for instance. We also have an idea about the possible use of this type. Hence, we can decide what kind of operations are needed.

Our first step is to determine functionality. Thinking about the data type and its possible use, we determine what operations are needed to create instances of the data type, modify these instances, and obtain values from the data type.

For example, we need to:

Do we need any more operations? That depends on the way we intend to use the type we are building. It may be useful to add other operations for SET, such as union, intersection, etc. We will keep things simple, and identify our operations as newset, add, delete, member, empty and size.
The next step is to write the signatures. Remember, signatures are operators expressed as mathematical functions.

Using INTEGERS and BOOLEAN as types, we have:

 newset:               --------> SET

 add   : SET x INTEGER --------> SET

 delete: SET x INTEGER --------> SET

 member: SET x INTEGER --------> BOOLEAN

 empty : SET           --------> BOOLEAN

 size  : SET           --------> INTEGER


Next, we must choose constructors. Among the operators mentioned above, newset and add are the constructors. Any SET can be constructed using only these two operators.

Finally, we write the axia. We only need to consider the composition of each non-constructor operator from some combination of constructor operators. Thus, we only consider:

Having this list at hand, we need to express each statment in a way reflecting how the operators interact. This may be done as follows:
  1. delete(newset,I) = newset
  2. delete(add(S,I),J) = S if I=J else add(delete(S,J),I)
  3. member(newset,I) = false
  4. member(add(S,I),J) = true if I=J else member(S,J)
  5. empty(newset) = true
  6. empty(add(S,I)) = false
  7. size(newset) = 0
  8. size(add(S,I)) = size(S)+1 if I is not in S else size(S)
NOTES:

In the implementation process we will be faced with an issue concerning term equality. That is, what is meant by stating that two things are equal? For example, to state that two sets are equal, it means they have the same elements (regardless of the order in which they appear). This "equality function" must be defined in order for us to check the correctness of our implementation for the axia.


Goto Previous Topic Goto Next Topic
Created 02/16/98 by salama
Revised 4/28/98