logo
 
Abstract Data Types
CptS 355 - Programming Language Design
Washington State University
Home
Notices
Calendar
Homework
Syllabus
Resources
People

Names, Modularity, and Maintainability

In large programs, unless they are designed correctly, it is difficult to anticipate the results of modifying or adding code. Subprograms are a way of breaking up processes to abstract a commonly used piece of code and to isolate the effect of changes or modifications to code. Objects, packages, and abstract data types are ways of abstracting data, to encapsulate data structures. First we will look at ADTs, then at methods to help declutter name spaces.

Abstraction

What is abstraction? In general, elimination of details. In programming abstraction often means describing the "what" not "how". The notion of "interface" is one way that abstraction appears in programming. Informally, the interface of a component is the rules for using the component. It tells you what operations the component has, the way to use them, and what they will do. In some languages the notion of interface appears directly and concretely as syntax in the language.

Note: Interfaces in Java are a bit at odds with the above definition. Java interfaces are used in place of multiple inheritance so no one Java interface necessarily describes the whole interface, in the sense I'm using it here, of a class.

Example of how abstraction helps: compare how strings are handled in perl and C. In perl, strings are abstract: you don't know or care about their representation. There is just a set of "string-ish" operations that can be applied to them. In C, strings are arrays of characters. There are library routines to do "string-ish" operations but the "array-ness" shows through everywhere, making string manipulations in C much more tedious and error-prone than in Perl.

Abstract Data Types

Recall that a type is a set of values and a set of allowable operations on those values. Floating point type, such as Pascal type real
  • Historically - different architectures have supported different floating point represenations
  • Some operations supported, +, -, *
  • Actual layout of bits is (or should be) hidden
What about ability to define new types? A abstract data type is
  • The declarations of the type and the operations on the type, defined in a single syntactic unit.
  • The representation is hidden.
An example of an abstract data type: a stack.
  • values - a stack of integers
  • operations - push, pop, create, destroy, full
An example C Stack ADT. First there is the definition of the ADT, in a header file.
/* In stack.h */
typedef struct {
  int values[];
  int top;
  } stack_type;

/* operations */
void push(stack_type stack, int value);
int pop(stack_type stack);
int isEmpty(stack_type stack);
stack_type newStack(int capacity);
stack_type destroy();
Next there is the implementation of the stack.
/* In stack.c */
#include "stack.h"

/* operations */
void push(stack_type stack, int value) {
 ....
 }
int pop(stack_type stack) {
 ...
 }
...
Finally, there is the use of the stack.
/* In main.c */
#include "stack.h"

main() {
  stack_type stack;

  push(stack, 23);         /* Should be an Error! */
  stack = newStack(50);
  
  stack.values[30] = 100;  /* Shouldn't be able to do this! */
  }
Unsatisfactory because
  • stack type internals are not hidden, main.c knows about stack internals. This dramatically reduces reliability.
  • can't hide
  • stack type objects are not "protected" in the sense that other operations could manipulate the internals of the stack object
  • stack use/definition separate: potentially, user could cut and paste stack.h into main, then any changes to stack.h would not be manifest in main.c.
  • not like an integer, type cannot be enforced by compiler, user doesn't have to do a newStack prior to using a stack!
  • name conflicts galore - what if user wants a list type, and has a pop operation on lists?
  • allocation/deallocation up to the user
  • non-orthogonal of type of elements in stack, why can't I have a stack of chars?
Ada was designed to help.
  • Largest language design effort in history
  • 1974 - Department of Defense begins design
  • 1978 - Requirements docment completed, design goes to bid
  • 1979 - Four designs proposed, evaluation begins
  • 1979 - One design chosen, called Ada, opened for public comment and 500 language reports received
  • 1981 - 1983 - Language is standardized
  • Designed by committee, had lots of features
  • 1985 - First compilers appear
Kinds of operations in an ADT
  • constructor - create an object, usually heap-dynamic, but sometimes stack-dynamic
  • destructor - destroy the object, freeing space. Object should not be used after the destructor (how do we guarantee?).
  • accessor - read a value in the object
  • iterator - enumerate values in the object
  • mutator - modify the object
Ada example of stack encapsulation.
  -- In Ada.stack file
  package Stack_Pack is
   -- Public interface, visible to outside world
   type Stack_Type is limited private;
   Max_Size : constant : 100;
   function Push(Stk : in out Stack_Type, Element : in Integer): Boolean;
   function Pop(Stk : in out Stack_Type): Integer;
   ...
   private
    -- hidden from clients
    type Stack_Type is array (1..Max_Size) of Integer; 
  end Stack_Pack;
Then there is the body of the stack.
  -- In stack.ada
  package body Stack_Pack is
    function Push(Stk : in out Stack_type; Element : in Integer) : boolean
      is begin
        ...
      end Push;
    ...
  end Stack_Pack;
These two would be compiled with the code that uses the stack.
 with Stack_Pack;  -- makes names defined in Stack_Pack visible here
 use Stack_Pack;   -- do not have to qualify those names
 procedure Use_stacks is
   Stack: Stack_Type;  -- constructor!
   begin
     if (!Push(Stack, 42)) then ...
     ...
   end Use_stacks; -- Stack is deallocated
  • Can choose to hide or make public
  • Specification part and implementation part compiled together
  • Allocation/deallocation implicit
  • Can create a generic package to create stacks of different types
      Package Float_Stack is new Generic_Stack(500, Float);
    
  • Potential for name space conflicts still exist, and have to keep passing stack as a parameter.
C++ ADT.
/* In stack.h */
class stack {
 private: //** Visible only here (and to friends)
   int  *stackPtr;
   int  maxSize;
   int  *top; 
 public: 
   stack() {  //** constructor
     stackPtr = new int [100];
     ...
     }
   stack(int size) {  //** constructor
     stackPtr = new int [size];
     ...
     }
   ~stack() {delete [] stackPtr;}; //** Destructor
   void push(int number) { ... }
   ...
 } //** class stack
/* In main.cc */
#include 
void main() {
  stack stk;  //** Calls the constructor, create a new instance
  stk.push(42);
  ...
  } //** Destructor called for stk
Operator "overloading" refers to an operator changing depending upon the type of the operands. Languages that support the definition of abstract data types should also allow operator overloading so that new types can be used with existing operators. Parameterising the data type.
  • value parameter - a value passed to the abstract data type on creation of a variable of that type, e.g., capacity could be a parameter
      stack_type st(3);  /* Create a stack of size 3 */
    
  • type parameter - a type passed a value to the abstract data type on creation of a variable of that type, e.g., the type of items in the stack could be fixed only during the stack creation
  •   stack_type st(char, 3);  /* Create a stack of characters of size 3*/
    
    Compiler generates different code.

Packages

A package is a group of declared components, e.g., types, constants, variables, functions. It is an encapsulated set of bindings Example Package
  
package Earth is
    constant float gravity = 9.6;
    constant integer circumference = 29000;
    ...
    type continent is (Africa, ..., SudAmerica);
  end Earth;
is set of bindings
  
  gravity --> 9.6
  circumference --> 29000
  ...
  continent --> the type {Africa, ..., SudAmerica}
But note that a package defines just a single environment. Environments often has many bindings in common, such as one would expect Jupiter to have a similar set of bindings as Earth.

Source of Information

These lecture notes are based on Chapter 11 in "Programming Languages, 6ed" by Robert Sebesta and Chapter 6 in "Programming Language Concepts and Paradigms" by David Watt.
                                                                                                                                                                                                                                                                                                                                             
  (c) 2003 Curtis Dyreson, (c) 2004 Carl H. Hauser           E-mail questions or comments to Prof. Carl Hauser