Adding new generators

Instructor's Guide


intro, types, algebra, modules, classes, summary, Q/A, literature
Abstract data types were developed with correctness and security in mind, and not so much from a concern with extensibility and reuse. Nevertheless, it is interesting to compare the traditional approach of realizing abstract data types (employing modules) and the object-oriented approach (employing objects as generator subtypes) with regard to the ease with which a specification may be extended, either by adding new generators or by adding new observers.

Adding new generators -- representation

ADT


  typedef int element;
  
  enum { NIL, CONS, INTERVAL };
  
  struct list {
  int tag;
  element e; 
  union { element z; list* next; };
  };
  

Generator

  list* interval( element x, element y ) {
  	list* l = new list;
  	if ( x <= y ) {
  		l->tag = INTERVAL;
  		l->e = x; l->z = y;
  		}
  	else l->tag = NIL;
  	return l;
  	}
  

slide: Modules and generators

Let us first look at what happens when we add a new generator to a data type, such as an interval list subtype, containing the integers in the interval between two given integers. For the module realization of the list, adding an interval(x,y) generator will result in an extension of the (hidden) representation types with an additional representation tag type INTERVAL and the definition of a suitable generator function. To represent the interval list type, we employ a union to select between the next field, which is used by the cons generator, and the z field, which indicates the end of the interval.

Modifying the observers

ADT


  element head(list* l) {  
head
require( ! empty(l) ); return l->e;
for both CONS and INTERVAL
} list* tail(list* l) {
tail
require( ! empty(l) ); switch( l->tag ) { case CONS: return l->next; case INTERVAL: return interval((l->e)+1,l->z); } }

slide: Modifying the observers

Also, we need to modify the observer functions by adding an appropriate case for the new interval representation type, as pictured in slide 8-mod-xx. Clearly, unless special constructs are provided, the addition of a new generator case requires disrupting the code implementing the given data type manually, to extend the definition of the observers with the new case. In contrast, not surprisingly, when we wish to add a new generator case to the object realization of the list, we do not need to disrupt the given code, but we may simply add the definition of the generator subtype as given in slide 8-oop-gen.

Adding new generators

OOP


  class interval : public list<int> { 
interval
public: interval(int x, int y) : _x(x), _y(y) { require( x <= y ); } bool empty() { return 0; } int head() { return _x; } list< int >* tail() { return (_x+1 <= _y)? new interval(_x+1,_y): new nil<int>; } bool operator==(list@lt;int>* m) { return !m->empty() && _x == m->head() && tail() == m->tail(); } protected: int _x; int _y; };

slide: Objects and generators

Adding a new generator subtype corresponds to defining the realization for an abstract interface class, which gives a method interface that its subclasses must respect. Observe, however, that we cannot exploit the fact that a list is defined by an interval when testing equality, since we cannot inspect the type of the list as for the ADT implementation.