Presentation is loading. Please wait.

Presentation is loading. Please wait.

Abstract Data Types and Modules

Similar presentations


Presentation on theme: "Abstract Data Types and Modules"— 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 real operations: +: 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: real axioms: 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 boolean operations: createq: queue enqueue: queue  element  queue dequeue: queue  queue frontq: queue  element emptyq: queue  boolean constant

12 An Example – Queue variables: q: queue; x: element axioms: 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 boolean operations: createstk: stack push: stack  element  stack pop: stack  stack top: stack  element emptystk: stack  boolean

17 An Example – Stack variables: s: stack; x: element axioms: 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 list with val createq = Q [ ]; fun enqueue (Q lis, elem) = Q [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 Queue fun enqueue = fn : ‘a Queue * ‘a -> ‘a Queue fun 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 * real with val 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 namespace MyQueue { 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 file package myqueue; Names can be dereferenced using import 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 [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

51 An Example - Queue - open Queue1; opening Queue1
datatype 'a Queue = Q of ‘a list 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

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

53 An Example – Queue2 structure Queue2: QUEUE = struct
datatype 'a Queue = Createq | Enqueue of 'a Queue * 'a ; val createq = Createq; fun enqueue(q,elem) = Enqueue (q,elem); fun frontq (Enqueue(Createq,elem)) = elem | frontq (Enqueue(q,elem)) = frontq q; fun dequeue (Enqueue(Createq,elem)) = Createq | dequeue (Enqueue(q,elem)) = Enqueue(dequeue q, elem); fun emptyq Createq = true | emptyq _ = false; end;

54 An Example – Queue2 - open Queue2; opening Queue2
datatype 'a Queue = Createq | Enqueue of 'a Queue * 'a ; 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

55 An Example – Queue2 - val q = enqueue(createq,3);
val q = Enqueue (Createq, 3) : int Queue - frontq q; val it = 3 : int - val q1 = dequeue q; val q1 = Createq : int Queue - emptyq q1; val it = true : bool

56 Problems Modules are not types Modules are static entities
Modules that export types do not adequately control operations on variables of such types Modules do not always adequately represent how they depend on imported types Modules include no specification of the semantics of the provided operations

57 Modules Are Not Types ML contains both an abstract data type mechanism and a module mechanism to emphasize this distinction An abstype is a type, but the implementation of an abstype cannot be separated from its specification, and clients implicitly depend on the implementation The module mechanism is more general, and it allows the clean separation of specification from implementation, but a type must be exported

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

59 Introduction to Programming Languages
ML Example - Queue type ‘a Queue val createq = - : ‘a Queue fun enqueue = fn : ‘a Queue * ‘a -> ‘a Queue fun dequeue = fn : ‘a Queue -> ‘a Queue fun frontq = fn : ‘a Queue -> ‘a fun emptyq = fn : ‘a Queue -> bool Abstract Data Types and Modules

60 Modules Are Static Entities
A possibility for implementing an abstract data type is to simply not reveal a type at all, thus avoiding all possibility of clients depending in any way on implementation details, as well as preventing clients from any misuse of a type

61 Ada Example - Queue generic type T is private; package Queues is
procedure enqueue(elem:T); function frontq return T; procedure dequeue; function emptyq return Boolean; end Queues;

62 Ada Example - Queue package body Queues is type Queuerep;
type Queue is access Queuerep; type Queuerep is record data: T; next: Queue; end record; q: Queue; procedure enqueue(elem:T) 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; q := temp; end enqueue;

63 Ada Example - Queue function frontq return T is
begin return q.next.data; end frontq; procedure dequeue is begin if q = q.next then q := null; else q.next := q.next.next; q := q.next; end if; end dequeue; function return Boolean is begin return q = null; end emptyq; begin q := null; end Queues;

64 Ada Example - Queue with Queues; procedure Quser is
package Queue1 is new Queues(Integer); package Queue2 is new Queues(Integer); begin Queue1.enqueue(3); Queue1.enqueue(4); Queue2.enqueue(1); Queue2.enqueue(2); put(Queue1.frontq); new_line; Queue2.dequeue; put(Queue2.frontq); new_line; end Quser;

65 Modules Not Adequately Control Operations
Variables of abstract data types are pointers that had to be allocated and initialized by calling procedures like createq and makeComplex. But the module cannot guarantee that these procedures are called before the variables are used Since variables are pointers, copies can be made and deallocation performed outside the control of the module

66 Ada Example z := makeComplex(1.0, 0.0); x := makeComplex(-1.0, 0.0); x := z; x := makeComplex(1.0, 0.0); y := makeComplex(1.0, 0.0); (* now a test of x = y return false *)

67 Ada Example package ComplexNumbers is type Complex is limited private;
function "+"(x,y: 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; function equal(x, y: in Complex) return Boolean; procedure assign(x: out Complex; y: in Complex); private type ComplexRec; type Complex is access ComplexRec; end ComplexNumbers;

68 ML Example signature QUEUE = sig eqtype ’’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;

69 Modules Not Adequately Represent How They Depend on Imported Types
Aside from assignment and equality testing, modules often depend on the existence of certain operations on type parameters and may also call functions whose existence is not made explicit in the module specification

70 C++ Example template <typename T> T min(T x, T y);
T min(T x, T y) { return x < y ? x : y }

71 Ada Example generic type Element is private;
with function lessThan (x, y: Element) return Boolean; package OrderedList is end Queues; package IntOrderedList is new OrderedList(Integer, “<“);

72 ML Example signature ORDER = sig type Elem
val lt: Elem * Elem -> bool end; signature ORDERED_LIST = type OList val create: OList val insert: OList * Elem -> OList val lookup: OList * Elem -> bool

73 ML Example functor OListFUN (structure Order: ORDER): ORDERED_LIST =
type Elem = Order.Elem; type OList = Order.Elem list; val create = []; fun insert ([], x) = [x] | insert (h::t, x) = if Order.lt(x,h) then x::h::t else h:: insert (t, x); fun lookup ([], x) = false | lookup (h::t, x) = if Order.lt(x,h) then false else if Order.lt(h,x) then lookup (t,x) else true; end;

74 ML Example structure IntOrder: ORDER = struct type Elem = int;
val lt = (op <); end; structure IntOList = OListFUN(structure Order = IntOrder);

75 ML Example - val ol = insert(create,2); - open IntOList;
val ol = [2] : OList - val ol2 = insert(ol,3); val ol2 = [2, 3] : OList - lookup (ol2,3); val it = true : bool - lookup (ol,3); val it = false : bool - open IntOList; opening IntOList type Elem = IntOrder.Elem type OList = IntOrder.Elem list val create: OList val insert: OList * Elem -> OList val lookup: OList * Elem -> bool

76 Modules Include No Specification of the Semantics of Operations
One example of a language that does allow the specification of semantics is Eiffel, an object-oriented language

77 Eiffel Example frontq(enqueue(q, x)) = if emptyq(q) then x else frontq(q) emptyq(enqueue(q, x)) = false enqueue (x: element) is require not full ensure if old empty then front = x else front = old front; not empty end; precondition postcondition


Download ppt "Abstract Data Types and Modules"

Similar presentations


Ads by Google