1 / 77

Abstract Data Types and Modules

Abstract Data Types and Modules. Builtin Data Types. Builtin data types are designed to insulate the user of a language from the implementation of the data type, which is machine dependent

gyula
Download Presentation

Abstract Data Types and Modules

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Abstract Data Types and Modules

  2. Builtin Data Types • Builtin data types are designed to insulate the user of a language from the implementation of the data type, which is machine dependent • These data types can be manipulated by a set of builtin operations, whose implementation details are also hidden from the user. The semantics of these operations are completely specified in the language definition

  3. User-Defined Data Types • User-defined data types are built up from data structures created using the builtin data types and type constructors. Their data structures are visible to the user • User-defined data types do not come with any operations other than the accessing operations of the data structures themselves. The functions defined to manipulate a data structure are not directly associated with its data type. The implementation details of these functions are also visible to the user

  4. Abstract Data Types - Specification • Abstract data types (ADT) provide a method for defining a data type and at the same time operations on that type. The operations should be directly associated with the type • The definitions should not depend on any implementation details • The definitions of the operations should include a specification of their semantics

  5. Abstract Data Types - Implementation • A method for collecting the implementation details of the type and its operations in one place • A method for restricting access to these implementation details by programs that use the data type

  6. Abstract Data Types • Modifiability is enhanced by interfaces that are implementation independent, since changes can be made to an implementation without affecting its use by the rest of the program • Security is enhanced by protecting the implementation details from arbitrary modification by other part of the program • Reusability is enhanced by standard interfaces, since the code can be reused by different programs

  7. Abstract Data Types • Encapsulation refers to the collection of all definitions related to a data type in one location and restricting the use of the type to the operations defined at that location • Information hiding refers to the separation of implementation from these definitions and the suppression of these details in the use of the data type

  8. Algebraic Specification • Syntactic specification includes the name of the type and the names of the operations, including a specification of their parameters and returned values. Function notation of mathematics is often used • Semantics specification includes the properties that the operations must possess. In mathematics, the properties of functions are often described by equations or axioms

  9. An Example – Complex Numbers type complex imports realoperations: +: complex  complex  complex -: complex  complex  complex *: complex  complex  complex /: complex  complex  complex -: complex  complex makecomplex: real  real  complex realpart: complex  real imaginarypart: complex  real

  10. An Example – Complex Numbers variables: x, y, z: complex; r, s: realaxioms: realpart(makecomplex(r, s)) = r imaginarypart(makecomplex(r, s)) = s realpart(x+y) = realpart(x) + realpart(y) imaginarypart(x+y) = imaginarypart(x) + imaginarypart(y) realpart(x-y) = realpart(x) - realpart(y) imaginarypart(x-y) = imaginarypart(x) - imaginarypart(y) …

  11. An Example – Queue parameterized type queue(element) imports booleanoperations: createq: queue enqueue: queue  element  queue dequeue: queue  queue frontq: queue  element emptyq: queue  boolean constant

  12. An Example – Queue variables: q: queue; x: elementaxioms: emptyq(createq) = true emptyq(enqueue(q, x)) = false frontq(createq) = error frontq(enqueue(q, x)) = if emptyq(q) then x else frontq(q) dequeue(createq) = error dequeue(enqueue(q, x)) = if emptyq(q) then q else enqueue(dequeue(q), x) error axiom

  13. Constructors and Inspectors • An operation that creates a new object of the data type being defined is called a constructor. Operations createq and enqueue are constructors • An operation that retrieves previously constructed values is called an inspector. Operations dequeue, frontq, and emptyq are inspectors

  14. Predicates and Selectors • Inspectors that return Boolean values are called predicates. Inspector emptyq is a predicate • Inspectors that return non-Boolean values are called selectors. Inspectors dequeue and frontq are selectors

  15. Finding Axiom Set • In general, one needs one axiom for each combination of an inspector with a constructor emptyq(createq) emptyq(enqueue(q, x)) frontq(createq) frontq(enqueue(q, x)) dequeue(createq) = error dequeue(enqueue(q, x))

  16. An Example – Stack type stack(element) imports booleanoperations: createstk: stack push: stack  element  stack pop: stack  stack top: stack  element emptystk: stack  boolean

  17. An Example – Stack variables: s: stack; x: elementaxioms: emptystk(createstk) = true emptystk(push(s, x)) = false top(createstk) = error top(push(s, x)) = x pop(createstk) = error pop(push(s, x)) = s

  18. Abstract Data Type Mechanisms • A mechanism must have a way of separating the specification and implementation of an ADT • A mechanism must also guarantee that any code outside the ADT definition cannot use details of the implementation, but can operate on a value of the defined type only through the provided operations

  19. ML Example - Queue abstype ‘element Queue = Q of ‘element listwithval createq = Q [ ];fun enqueue (Q lis, elem) = Q (lis @ [elem]);fun dequeue (Q lis) = Q (tl lis);fun frontq (Q lis) = hd lis;fun emptyq (Q [ ]) = true | emptyq (Q (h::t)) = false;end;

  20. ML Example - Queue type ‘a Queue val createq = - : ‘a Queuefun enqueue = fn : ‘a Queue * ‘a -> ‘a Queuefun dequeue = fn : ‘a Queue -> ‘a Queue fun frontq = fn : ‘a Queue -> ‘a fun emptyq = fn : ‘a Queue -> bool

  21. ML Example - Queue - val q = enqueue(createq, 3); val q = - : int Queue - val q2 = enqueue(q, 4); val q2 = - : int Queue - frontq q2; val it = 3 : int - val q3 = dequeue q2; val q3 = - : int Queue - frontq q3; val it = 4 : int

  22. ML Example – Complex Numbers abstype Complex = C of real * realwithval makecomplex (x, y) = C (x, y);fun realpart (C (r, i)) = r;fun imaginarypart (C (r, i)) = i;fun +: (C (r1, i1), C (r2, i2)) = C (r1+r2, i1+i2);infix 6 +: ; (* other operations *) end;

  23. ML Example – Complex Numbers - val z = makecomplex(1.0, 2.0); val z = - : Complex - val w = makecomplex(2.0, ~1.0); val w = - : Complex - val x = z +: w; val x = - : Complex - realpart x; val it = 3.0 : real - imaginarypart x; val it = 1.0 : real

  24. Modules • An ADT mechanism may not fit a package of related functions that do not associate directly with a data type • A mathematical function package consisting of the standard functions such as sine, cosine, exponential, and logarithmic functions is an example • A module mechanism is used in such cases

  25. Modules • A module is a program unit with a public interface and a private implementation; all services that are available from a module are described in its public interface and are exported to other modules, and all services that are needed by a module must be imported from other modules • As providers of services, modules can export any mix of data types, procedures, variables, and constants

  26. Modules • Because modules have explicit (public) interfaces and separate (private) implementations, they are ideal mechanisms to provide separate compilation and library facilities within a software development environment • The interface for each module is kept in textual form and is needed at the compile time, while the implementation may only be provided as object code and is only needed at the link time

  27. Modules • Modules are an essential tool in program decomposition and complexity control • Modules provide additional scope features that make the task of name control more manageable • Module mechanism can document the dependencies of a module on other modules by requiring explicit import lists whenever code from other modules is used

  28. Separate Compilation in C queue.h(interface) queue.c(implementation) q_user.h(client)

  29. queue.h #ifndef QUEUE_H #define QUEUE_H struct Queuerep; typedef struct Queuerep * Queue; Queue createq(void); Queue enqueue(Queue q, void* elem); void* frontq(Queue q); Queue dequeue(Queue q); int emptyq(Queue q); #endif

  30. queue.c #include "queue.h" #include <stdlib.h> struct Queuerep { void* data; Queue next; }; Queue createq(void) { return 0; } Queue enqueue(Queue q, void* elem) { Queue temp = malloc(sizeof(struct Queuerep)); temp->data = elem; if (q) { temp->next = q->next; q->next = temp; q = temp; } else { q = temp; q->next = temp; } return q; }

  31. queue.c void* frontq(Queue q) { return q->next->data; } Queue dequeue(Queue q) { Queue temp; if (q == q->next) { temp = q; q = 0; } else { temp = q->next; q->next = q->next->next; } free(temp); return q; } int emptyq(Queue q) { return q == 0; }

  32. q_user.c #include <stdlib.h> #include <stdio.h> #include "queue.h" main() { int *x = malloc(sizeof(int)); int *y = malloc(sizeof(int)); int *z; Queue q = createq(); *x = 2; *y = 3; q = enqueue(q,x); q = enqueue(q,y); z = (int*) frontq(q); printf("%d\n",*z); /* prints 2 */ q = dequeue(q); z = (int*) frontq(q); printf("%d\n",*z); /* prints 3 */ return 0; } User can directly copy declarations in queue.h here User can directly copy the definition of Queuerep here

  33. C++ Namespaces - queue.h #ifndef QUEUE_H #define QUEUE_H namespaceMyQueue { struct Queuerep; typedef Queuerep * Queue; Queue createq(); Queue enqueue(Queue q, void* elem); void* frontq(Queue q); Queue dequeue(Queue q); bool emptyq(Queue q); } #endif

  34. queue.cpp namespace MyQueue { struct Queuerep { void* data; Queue next; }; Queue createq(void) { return 0; } Queue enqueue(Queue q, void* elem) { Queue temp = new Queuerep; temp->data = elem; if (q) { temp->next = q->next; q->next = temp; q = temp; } else { q = temp; q->next = temp; } return q; }

  35. queue.cpp void* frontq(Queue q) { return q->next->data; } Queue dequeue(Queue q) { Queue temp; if (q == q->next) { temp = q; q = 0; } else { temp = q->next; q->next = q->next->next; } delete temp; return q; } bool emptyq(Queue q) { return q == 0; } } // end namespace MyQueue

  36. q_user.cpp #include <iostream> #include "queue2.h" using std::endl; using namespace MyQueue; main() { int *x = new int; int *y = new int; int *z; Queue q = MyQueue::createq(); *x = 2; *y = 3; q = enqueue(q,x); q = enqueue(q,y); z = (int*) frontq(q); // explicit qualification needed for cout std::cout << *z << endl; // prints 2 q = dequeue(q); z = (int*) frontq(q); std::cout << *z << endl; // prints 3 }

  37. Java Packages • Packages are constructed as groups of related classes • Each separately compiled file is allowed to have only one public class, and this class can be placed in a package by writing a package declaration at the beginning of the filepackage myqueue; • Names can be dereferenced usingimport myqueue.Queue;import myqueue.*;

  38. Ada Packages • An Ada package is divided into a package specification and a package body • A package specification is the public interface to the package

  39. An Example – Complex Numbers package ComplexNumbers is type Complex is private; function "+"(x,y: in Complex) return Complex; function "-"(x,y: in Complex) return Complex; function "*"(x,y: in Complex) return Complex; function "/"(x,y: in Complex) return Complex; function "-"(z: in Complex) return Complex; function makeComplex (x,y: in Float) return Complex; function realPart (z: in Complex) return Float; function imaginaryPart (z: in Complex) return Float; private type ComplexRecord; type Complex is access ComplexRecord; end ComplexNumbers;

  40. An Example – Complex Numbers package body ComplexNumbers is type ComplexRecord is record re, im: Float; end record; function "+"(x,y: in Complex) return Complex is t: Complex; begin t := new ComplexRecord; t.re := x.re + y.re; t.im := x.im + y.im; return t; end "+"; -- more operations here

  41. An Example – Complex Numbers function makeComplex (x,y: in Float) return Complex is begin return new ComplexRecord'(re => x , im => y); end makeComplex; function realPart (z: in Complex) return Float is begin return z.re; end realPart; function imaginaryPart (z: in Complex) return Float is begin return z.im; end imaginaryPart; end ComplexNumbers;

  42. An Example – Complex Numbers with ComplexNumbers; use ComplexNumbers; procedure ComplexUser is z,w: ComplexNumbers.Complex; begin z := ComplexNumbers.makeComplex(1.0,-1.0); w := ComplexNumbers."+"(z,z); w := z + z; end ComplexUser;

  43. An Example – Queues generic type T is private; package Queues is type Queue is private; function createq return Queue; function enqueue(q:Queue;elem:T) return Queue; function frontq(q:Queue) return T; function dequeue(q:Queue) return Queue; function emptyq(q:Queue) return Boolean; private type Queuerep; type Queue is access Queuerep; end Queues;

  44. An Example – Queues package body Queues is type Queuerep is record data: T; next: Queue; end record; function createq return Queue is begin return null; end createq; function enqueue(q:Queue;elem:T) return Queue is temp: Queue; begin temp := new Queuerep; temp.data := elem; if (q /= null) then temp.next := q.next; q.next := temp; else temp.next := temp; end if; return temp; end enqueue;

  45. An Example – Queues function frontq(q:Queue) return T is begin return q.next.data; end frontq; function dequeue(q:Queue) return Queue is begin if q = q.next then return null; else q.next := q.next.next; return q.next; end if; end dequeue; function emptyq(q:Queue) return Boolean is begin return q = null; end emptyq; end Queues;

  46. An Example – Queues with Queues; procedure Quser is package IntQueues is new Queues(Integer); use IntQueues; package FloatQueues is new Queues(Float); use FloatQueues; fq: FloatQueues.Queue := createq; iq: IntQueues.Queue := createq; begin fq := enqueue(fq,3.1); fq := enqueue(fq,2.3); iq := enqueue(iq,3); iq := enqueue(iq,2); put(frontq(iq)); new_line; fq := dequeue(fq); put(frontq(fq)); new_line; end Quser;

  47. Modules in ML • ML module facility consists of three mechanisms: signatures, structures, and functors • A signature is an interface definition • A structure is an implementation of a signature • Functors are functions from structures to structures

  48. An Example - Queue signature QUEUE = sig type 'a Queue val createq: 'a Queue val enqueue: 'a Queue * 'a -> 'a Queue val frontq: 'a Queue -> 'a val dequeue: 'a Queue -> 'a Queue val emptyq: 'a Queue -> bool end;

  49. An Example - Queue structure Queue1: QUEUE = struct datatype 'a Queue = Q of 'a list val createq = Q [ ]; fun enqueue(Q lis, elem) = Q (lis @ [elem]); fun frontq (Q lis) = hd lis; fun dequeue (Q lis) = Q (tl lis); fun emptyq (Q [ ]) = true | emptyq (Q (h::t)) = false; end;

  50. An Example - Queue - val q = Queue1.enqueue(Queue1.createq,3); val q = Q [3] : int Queue1.Queue - Queue1.frontq q; val it = 3 : int - val q1 = Queue1.dequeue q; val q1 = Q [ ] : int Queue1.Queue - Queue1.emptyq q1; val it = true : bool

More Related