CSC 153: Computer Science Fundamentals Grinnell College Spring, 2005
 
Laboratory Exercise Reading
 

Introduction to Abstract Data Types

Abstract

This reading provides motivation for and a simple implementation of abstract data types. In subsequent labs, the concept of abstract data types will lead to an alternative approach to problem solving, called object-oriented programming.

Departmental Telephone Directories

Problem

On-line telephone directories are to be created for several departments. For each directory, one should be able to add names, delete names, correct a telephone number, look up an entry by name, and print the full directory.

Data Structure

A natural data structure for a directory would be an association list. Data for each individual would be stored as a (name, number) pair, and these pairs would be stored together on a list.

Observation

Writing code will be simplified significantly if we can be sure that data will be in an association list. Over time, however, additional code may be written, or other applications may be run in the same environment used for a directory. In such circumstances, we may want to ensure that other code will not change the structure of an association list.

In computer science, one approach to help guarantee that data structures will not be altered by other applications or code is to encapsulate the data and restrict what programs can access that data. This perspective motivates the concept of an abstract data type.

An abstract data type or ADT consists of a collection of data together with operations on that data. Further, the data and operations are packaged together, in such a way that only the specified operations may have direct access to the data. Other programs must use the specified ADT operations whenever those programs want to retrieve, store, or modify data within the ADT.

A Simple Scheme Implementation

Within Scheme, the definition for a (very simple) telephone directory might be as follows:

(define directory
   (lambda init-list
      (let ((assoc-list      ;; the ADT's data
                   (if (null? init-list)
                        '()
                        (car init-list))))
           (letrec           ;; the ADT's operations
               ((add-name         ;; add names to directory
                   (lambda (name-entry)
                      (set! assoc-list (cons name-entry assoc-list))))
                (look-up          ;; find a name in the directory
                   (lambda (name)
                      (assoc name assoc-list)))
                (show             ;; show current state of directory
                   (lambda ()
                      assoc-list))
               )             ;; end of local definitions
           (lambda (op . parameters)
              (case op       ;; process external requests   
                  ((add)     (add-name parameters))
                  ((lookup)  (look-up (car parameters)))
                  ((show)    (show))
                  (else "unknown operation")
              )
           )
         )
       )
   )
)

Before considering this directory definition in detail, we review how such a definition could be used. The following declaration creates a directory for some Mathematics/Computer Science faculty:

(define math-dir  
   (directory '(("Arnold Adelberg"     4201)  ("Marc Chamberland"    4207)
                ("Christopher French"  4661)  ("Benjamin Gum"        3127)
                ("Eugene Herman"       4202)  ("Charles Jepsen"      4203)
                ("Keri Kornelson"      4661)  ("Shonda Kuiper"       3806)
                ("Emily Moore"         4205)  ("Thomas Moore"        4206)  
                ("Samuel Rebelsky"     4410)  ("David Romano"        3309)
                ("Karen Shuman"        4927)  ("Nikolay Silkin"      4880)
                ("John Stone"          3181)  ("Henry Walker"        4208)  
                ("Royce Wolf"          4209))))

With these definitions, this ADT may be used though various commands:

(math-dir 'lookup "John Stone")
   ==> ("John Stone"          3181)
(math-dir 'lookup "Karen Thomson")
   ==> ()
(math-dir 'add "Karen Thomson" 3169)
(math-dir 'show)
   ==> (("Karen Thomson"       3169)  ("Arnold Adelberg"     4201)
        ("Marc Chamberland"    4207)  ("Christopher French"  4661)
        ("Benjamin Gum"        3127)  ("Eugene Herman"       4202)
        ("Charles Jepsen"      4203)  ("Keri Kornelson"      4661)
        ("Shonda Kuiper"       3806)  ("Emily Moore"         4205)
        ("Thomas Moore"        4206)  ("Samuel Rebelsky"     4410)
        ("David Romano"        3309)  ("Karen Shuman"        4927)
        ("Nikolay Silkin"      4880)  ("John Stone"          3181)  
        ("Henry Walker"        4208)  ("Royce Wolf"          4209))

Commentary

We now examine the ADT structure and usage in more detail. In summary, ADTs may be implemented in Scheme using the following general structure:

(define ADT-name
   (lambda initialization
      (let ((local variables and data structures, using initialization))
          (letrec ((definition of ADT operations))
              (lambda (op . parameters)
                 (case op
                    (collection of operation names and calls to ADT operations)
                 )
              )
           )
       )
   )
)

An ADT is a template for storing data and processing requests. The initial lambda expression indicates the ADT will produce an logical data/operations entity when called. To allow an ADT to be initialized (e.g., with directory data), the main lambda expression has an optional parameter.

The structure specifies local variables (e.g., an association list) in the opening let statement. Since the variables are declared locally, data within the ADT cannot be accessed directly by outside code. This guarantees that access to ADT data must be accessed through the specified ADT operations.

Details of various operations are given within a letrec statement. Again, such operations are defined within the ADT, so they cannot be called or changed by outside. However, since the letrec is nested within the let, these local operations can access the ADT's local data directly.

Since a user will request various operations, an ADT involves a lambda expression which returns results for each request. More specifically, a user will specify an operation op when using the ADT, and this operation may involve parameters. The ADT uses a case statement to determine which operation is being requested and to respond appropriately -- using the locally defined procedures as needed.

With this general definition of an ADT, we create specific variables for individual instances of the ADT. In addition to the math-dir above, for example, we could define a physics directory as follows:

(define physics-dir
       (directory '(("Robert Cadmus"  3016)
                    ("William Case"   3014)
                    ("Mark Schneider" 3018)
                    ("Paul Tjossem"   4289))))

This definition uses the directory to create an initialized physics directory (the directory procedure is run with an appropriate association list of data, returning an ADT structure).

Jargon

In object-oriented programming, and ADT is called a class, and an individual instance of an ADT (e.g., math-dir or physics-dir) is called an object. To use an established object, we identify the object, the desired operation, and any required data.


This document is available on the World Wide Web as

http://www.cs.grinnell.edu/~walker/courses/153.sp05/readings/reading-adt.shtml

created March 26, 1998
last revised February 3, 2005
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.