Abstract data type
Download
1 / 48

Abstract Data Type - PowerPoint PPT Presentation


  • 122 Views
  • Uploaded on

Abstract Data Type. C and Data Structures Baojian Hua [email protected] Data Types. A data type consists of: A collection of data elements (a type) A set of operations on these data elements Data types in languages: predefined: any language defines a group of predefined data types

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Abstract Data Type' - gabriel-albert


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Abstract data type

Abstract Data Type

C and Data Structures

Baojian Hua

[email protected]


Data types
Data Types

  • A data type consists of:

    • A collection of data elements (a type)

    • A set of operations on these data elements

  • Data types in languages:

    • predefined:

      • any language defines a group of predefined data types

      • C e.g.: int, char, float, double, …

    • user-defined:

      • allow programmers to define their own (new) data types

      • C e.g.: struct, union, …


Data type examples
Data Type Examples

  • Predefined:

    • type: int

    • elements: …, -2, -1, 0, 1, 2, …

    • operations: +, -, *, /, %, …

  • User-defined:

    • type: complex

    • elements: 1+3i, -5+8i, …

    • operations: new, add, sub, distance, …


Concrete data types cdt
Concrete Data Types (CDT)

  • An concrete data type:

    • both concrete representations and their operations are available

  • Almost all C predefined types are CDT

    • For instance, “int” is a 32-bit double-word, and +, -, …

    • Knowing this can do dirty hacks

    • See demo…


Abstract data types adt
Abstract Data Types (ADT)

  • An abstract data type:

    • separates data type declaration from representation

    • separates function declaration (prototypes) from implementation (definitions)

  • A language must some form of mechanism to support ADT

    • interfaces in Java

    • signatures in ML

    • (roughly) header files & typedef in C


Case study
Case Study

  • Suppose we’d design a new data type to represent complex number c:

    • a data type “complex”

    • elements: 3+4i, -5-8i, …

    • operations:

      • new, add, sub, distance, …

  • How to represent this data type in C (CDT, ADT or …)?


Complex number
Complex Number

// Recall the definition of a complex number c:

c = x + yi, where x,y \in R, and i=sqrt(-1);

// Some typical operations:

complex Complex_new (double x, double y);

complex Complex_add (complex c1, complex c2);

complex Complex_sub (complex c1, complex c2);

complex Complex_mult (complex c1, complex c2);

complex Complex_divide (complex c1, complex c2);

// Next, we’d discuss several variants of rep’s:

// CDT, ADT.


Cdt of complex interface types
CDT of Complex:Interface—Types

// In file “complex.h”:

#ifndef COMPLEX_H

#define COMPLEX_H

struct Complex_t

{

double x;

double y;

};

typedef struct Complex_t Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif


Client code
Client Code

// With this interface, we can write client codes

// that manipulate complex numbers. File “main.c”:

#include “complex.h”

int main ()

{

Complex_t c1, c2, c3;

c1 = Complex_new (3.0, 4.0);

c2 = Complex_new (7.0, 6.0);

c3 = Complex_add (c1, c2);

Complex_output (c3);

return 0;

}

Do we know c1, c2, c3’s concrete representation?

How?


Cdt complex implementation
CDT Complex: Implementation

// In a file “complex.c”:

#include “complex.h”

Complex_t Complex_new (double x, double y)

{

Complex_t c = {.x = x, .y = y};

return c;

}

// other functions are similar. See Lab1


Problem 1
Problem #1

int main ()

{

Complex_t c;

c = Complex_new (3.0, 4.0);

// Want to do this: c = c + (5+i6);

// Ooooops, this is legal:

c.x += 5;

c.y += 6;

return 0;

}


Problem 2
Problem #2

#ifndef COMPLEX_H

#define COMPLEX_H

struct Complex_t

{

// change to a more fancy one? Anger “main”…

double a[2];

};

typedef struct Complex_t Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif


Problems with cdt
Problems with CDT?

  • Operations are transparent.

    • user code have no idea of the algorithm

    • Good!

  • Data representations dependence

    • Problem #1: Client code can access data directly

      • kick away the interface

      • safe?

    • Problem #2: make code rigid

      • easy to change or evolve?


Adt of complex interface types
ADT of Complex:Interface—Types

// In file “complex.h”:

#ifndef COMPLEX_H

#define COMPLEX_H

// note that “struct complexStruct” not given

typedef struct Complex_t *Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif


Client code1
Client Code

// With this interface, we can write client codes

// that manipulate complex numbers. File “main.c”:

#include “complex.h”

int main ()

{

Complex_t c1, c2, c3;

c1 = Complex_new (3.0, 4.0);

c2 = Complex_new (7.0, 6.0);

c3 = Complex_add (c1, c2);

Complex_output (c3);

return 0;

}

Can we still know c1, c2, c3’s concrete representation?

Why?


Adt complex implementation 1 types
ADT Complex: Implementation#1—Types

// In a file “complex.c”:

#include “complex.h”

// We may choose to define complex type as:

struct Complex_t

{

double x;

double y;

};

// which is hidden in implementation.


Adt complex implementation continued
ADT Complex: Implementation Continued

// In a file “complex.c”:

#include “complex.h”

Complex_t Complex_new (double x, double y)

{

Complex_t c;

c = malloc (sizeof (*c));

c->x = x;

c->y = y;

return c;

}

// other functions are similar. See Lab1


Adt summary
ADT Summary

  • Yes, that’s ADT!

    • Algorithm is hidden

    • Data representation is hidden

      • client code can NOT access it

      • thus, client code independent of the impl’

  • Interface and implementation

  • Do Lab1


Polymorphism
Polymorphism

  • To explain polymorphism, we start with a new data type “tuple”

  • A tuple is of the form: (x, y)

    • xA, yB (aka: A*B)

    • A, B may be unknown in advance and may be different

  • E.g:

    • A=int, B=int:

      • (2, 3), (4, 6), (9, 7), …

    • A=char *, B=double:

      • (“Bob”, 145.8), (“Alice”, 90.5), …


Polymorphism1
Polymorphism

  • From the data type point of view, two types:

    • A, B

  • operations:

    • new (x, y); // create a new tuple with x and y

    • equals (t1, t2); // equality testing

    • first (t); // get the first element of t

    • second (t); // get the second element of t

  • How to represent this type in computers (using C)?


Monomorphic version
Monomorphic Version

  • We start by studying a monomorphic tuple type called “intTuple”:

    • both the first and second components are of “int” type

    • (2, 3), (8, 9), …

  • The intTuple ADT:

    • type: intTuple

    • elements: (2, 3), (8, 9), …

    • Operations:

      • tuple new (int x, int y);

      • int first (int t);

      • int second (tuple t);

      • int equals (tuple t1, tuple t2);


Inttuple cdt
IntTuple” CDT

// in a file “int-tuple.h”

#ifndef INT_TUPLE_H

#define INT_TUPLE_H

struct IntTuple_t

{

int x;

int y;

};

typedef struct IntTuple_t IntTuple_t;

IntTuple_t IntTuple_new (int n1, int n2);

int IntTuple_first (IntTuple_t t);

#endif


Or the inttuple adt
Or the “IntTuple” ADT

// in a file “int-tuple.h”

#ifndef INT_TUPLE_H

#define INT_TUPLE_H

typedef struct IntTuple_t *IntTuple_t;

IntTuple_t IntTuple_new (int n1, int n2);

int IntTuple_first (IntTuple_t t);

int IntTuple_equals (IntTuple_t t1,

IntTuple_t t2);

#endif

// We only discuss “tupleEquals ()”. All others

// functions left to you.


Equality testing

t1

t2

x

x

y

y

Equality Testing

// in a file “int-tuple.c”

int Tuple_equals (IntTuple_t t1, IntTuple_t t2)

{

return ((t1->x == t2->x) && (t1->y==t2->y));

}


Problems
Problems?

  • It’s ok if we only design “IntTuple”

  • But we if we’ll design these tuples:

    • (int, double), (int, char *), (double, double), …

  • Same code exists everywhere, no means to maintain and evolve

    • Nightmares for programmers

    • Remember: never duplicate code!


Polymorphism2
Polymorphism

  • Now, we consider a polymorphic tuple type called “tuple”:

    • “poly”: may take various forms

    • Every element of the type “tuple” may be of different types

    • (2, 3.14), (“8”, ‘a’), (‘\0’, 99), …

  • The “tuple” ADT:

    • type: tuple

    • elements: (2, 3.14), (“8”, ‘a’), (‘\0’, 99), …


The tuple adt
The Tuple ADT

  • What about operations?

    • tuple new (??? x, ??? y);

    • ??? first (tuple t);

    • ??? second (tuple t);

    • int equals (tuple t1, tuple t2);


Polymorphic type
Polymorphic Type

  • To resove this, C dedicates a special polymorphic type “void *”

    • “void *” is a pointer which can point to “any” concrete types (i.e., it’s compatible with any pointer type),

      • very poly…

    • long history of practice, initially “char *”

    • can not be used directly, use ugly cast

    • similar to constructs in others language, such as “Object”


The tuple adt1
The Tuple ADT

  • What about operations?

    • tuple newTuple (void *x, void *y);

    • void *first (tuple t);

    • void *second (tuple t);

    • int equals (tuple t1, tuple t2);


Tuple interface
tuple” Interface

// in a file “tuple.h”

#ifndef TUPLE_H

#define TUPLE_H

typedef void *poly;

typedef struct Tuple_t * Tuple_t;

Tuple_t Tuple_new (poly x, poly y);

poly first (Tuple_t t);

poly second (Tuple_t t);

int equals (Tuple_t t1, Tuple_t t2);

#endif TUPLE_H


Client code2
Client Code

// file “main.c”

#include “tuple.h”

int main ()

{

int i = 8;

Tuple_t t1 = Tuple_new (&i, “hello”);

return 0;

}


Tuple adt implementation

t

x

y

“tuple” ADT Implementation

// in a file “tuple.c”

#include <stdlib.h>

#include “tuple.h”

struct Tuple_t

{

poly x;

poly y;

};

Tuple_t Tuple_new (poly x, poly y)

{

tuple t = malloc (sizeof (*t));

t->x = x;

t->y = y;

return t;

}


Tuple adt implementation1

t

x

y

“tuple” ADT Implementation

// in a file “tuple.c”

#include <stdlib.h>

#include “tuple.h”

struct Tuple_t

{

poly x;

poly y;

};

poly Tuple_first (Tuple_t t)

{

return t->x;

}


Client code3
Client Code

#include “complex.h” // ADT version

#include “tuple.h”

int main ()

{

int i = 8;

Tuple_t t1 = Tuple_new (&i, “hello”);

// type cast

int *p = (int *)Tuple_first (t1);

return 0;

}


Equality testing1

t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #1 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return ((t1->x == t2->x)

&& (t1->y == t2->y));

// Wrong!!

}


Equality testing2

t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #2 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return (*(t1->x) == *(t2->x)

&& *(t1->y) == *(t2->y));

// Problem?

}


Equality testing3

t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #3 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return (equalsXXX(t1->x, t2->x)

&&equalsYYY(t1->y, t2->y));

// but what are “equalsXXX” and “equalsYYY”?

}


Function as arguments
Function as Arguments

// So in the body of “equals” function, instead

// of guessing the types of t->x and t->y, we

// require the callers of “equals” supply the

// necessary equality testing functions.

// The #4 try:

typedef int (*tf)(poly, poly);

int Tuple_equals (tuple t1, tuple t2,

tf eqx, tf eqy)

{

return(eqx (t1->x, t2->x)

&&eqy (t1->y, t2->y));

}


Change to tuple interface
Change to “tuple” Interface

// in file “tuple.h”

#ifndef TUPLE_H

#define TUPLE_H

typedef void *poly;

typedef int (*tf)(poly, poly);

typedef struct Tuple_t *Tuple_t;

Tuple_t Tuple_new (poly x, poly y);

poly Tuple_first (Tuple_t t);

poly Tuple_second (Tuple_t t);

int Tuple_equals (Tuple_t t1, Tuple_t t2,

tf eqx, tf eqy);

#endif TUPLE_H


Client code4
Client Code

// in file “main.c”

#include “tuple.h”

int main ()

{

int i=8, j=8, k=7, m=7;

Tuple_t t1 = Tuple_new (&i, &k);

Tuple_t t2 = Tuple_new (&j, &k);

Tuple_equals (t1, t2, Int_equals, Int_equals);

return 0;

}


Moral
Moral

  • void* serves as polymorphic type in C

    • mask all pointer types (think Object type in Java)

  • Pros:

    • code reuse: write once, used in arbitrary context

    • we’d see more examples later in this course

  • Cons:

    • Polymorphism doesn’t come for free

      • boxed data: data heap-allocated (to cope with void *)

    • no static or runtime checking (at least in C)

    • clumsy code

      • extra function pointer arguments


Function carrying data
Function-Carrying Data

  • Why we can NOT make use of data, such as passed as function arguments, when it’s of type “void *”?

  • Better idea:

    • Let data carry functions themselves, instead passing function pointers

    • such kind of data called objects


Function pointer in data
Function Pointer in Data

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

// note that if t1->x or t1->y has carried the

//equality testing functions, thenthe code

// could just be written as:

return (t1->x->equals (t1->x, t2->x)

&& t1->y->equals (t1->y, t2->y));

}

equals

equals_x

……

t1

x

equals_y

y

equals

……


Function pointer in data1

equals

n

x

y

Function Pointer in Data

// To cope with this, we should modify other

// modules. For instance, the “complex” ADT:

struct Complex_t

{

int (*equals) (poly, poly);

double a[2];

};

Complex_t Complex_new (double x, double y)

{

Complex_t c = malloc (sizeof (*c));

c->equals = Complex_equals;

…;

return n;

}


Function call
Function Call

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return(t1->x->equals (t1->x, t2->x)

&& t1->y->equals (t1->y,t2->y));

}

equals

t2

t1

x

a[0]

a[0]

x

y

a[1]

a[1]

y


Client code5
Client Code

// in file “main.c”

#include “complex.h”

#include “tuple.h”

int main ()

{

Complex_t c1 = Complex_new (1.0, 2.0);

Complex_t c2 = Complex_new (1.0, 2.0);

Tuple_t t1 = Tuple_new (c1, c2);

Tuple_t t2 = Tuple_new (c1, c2);

Tuple_equals (t1, t2); // dirty simple! :-P

return 0;

}


Object
Object

  • Data elements with function pointers is the simplest form of objects

    • object = virtual functions + private data

  • With such facilities, we can in principal model object oriented programming

    • In fact, early C++ compilers compiles to C

    • That’s partly why I don’t love object-oriented languages


Summary
Summary

  • Abstract data types enable modular programming

    • clear separation between interface and implementation

    • interface and implementation should design and evolve together

  • Polymorphism enables code reuse

  • Object = data + function pointers


ad