more on abstract data types noah mendelsohn tufts university email:...

36
More on Abstract Data Types Noah Mendelsohn Tufts University Email: [email protected] Web: http://www.cs.tufts.edu/~noah COMP 40: Machine Structure and Assembly Language Programming (Spring 2014)

Upload: aldous-stanley

Post on 03-Jan-2016

215 views

Category:

Documents


0 download

TRANSCRIPT

More on Abstract Data Types

Noah MendelsohnTufts UniversityEmail: [email protected]: http://www.cs.tufts.edu/~noah

COMP 40: Machine Structure and

Assembly Language Programming (Spring 2014)

© 2010 Noah Mendelsohn

Last time we covered

How data and pointers are stored in the computer’s memory

Abstraction, modularity, reuse, information hiding

The special role of void * and incomplete structures

Generalizing over values and types

2

Today Generalizing over computation

Function pointers

Iteration and mapping in a functional style

Boxed and unboxed data structures

© 2010 Noah Mendelsohn

Quick Review

© 2010 Noah Mendelsohn

Software structures model real world objects and concepts

Integers

Students

Bank statements

Photographic images

Sound recordings

Etc.

4

These things aren’t bits!!

They don’t live in computers, but…

© 2010 Noah Mendelsohn

Software structures model real world objects and concepts

Integers

Students

Bank statements

Photographic images

Sound recordings

Etc.

5

We build data structures that model them

The course materials refer to these is being in the “World of Ideas”

© 2010 Noah Mendelsohn

Key principles to watch for

Abstraction – Refers to the act of “pulling away from” something so that unimportant details

are hidden”1

Modularity & clean interfaces– Each module “does one thing well” 2

Information hiding– Modules keep details of their internals secret

Generalization– When practical, each module or service should be as generally useful as

possible

6

1 Prof. Mark Sheldon – COMP 11 Big Ideas 2 Ken Thompson, co-inventor of Unix – The Unix Philosophy

© 2010 Noah Mendelsohn

Interfaces

7

Inte

rface

ImplementationClient

E.g. your fgroups program

E.g. implementation ofHanson Table_T

E.g. methods in Hanson table.h

© 2010 Noah Mendelsohn

Interfaces

8

Inte

rface

ImplementationClient

Many different programs can re-use the interface and the implementation!

The implementation chooses a representation … NOT visible to the client

© 2010 Noah Mendelsohn

Interfaces

9

Inte

rface

ImplementationClient

E.g. your fgroups program

E.g. implementation ofHanson Table_T

E.g. methods in Hanson table.h

My_table = Table_new(… … …)

Q. What can Table_new return?

I will show you two ways of doing this

A. A pointer to data you can’t look at

You will use this pointer to identify the new table

© 2010 Noah Mendelsohn

Client doesn’t know secret implementation

10

Inte

rface

ImplementationClient

my_table = Table_new(… … …)

Struct Table_t { …data declartions…}

struct Table_T *table_ptr;

void *table_ptr;

© 2010 Noah Mendelsohn

Client doesn’t know secret implementation

12

Inte

rface

ImplementationClient

my_table = Table_new(… … …)

Struct Table_t { …data declartions…}

struct Table_T *table_ptr;

void *table_ptr;

Note: These declarations are in the declaration

(either in a table.c, or in a tableimp.h)

© 2010 Noah Mendelsohn

Hanson does this with incomplete structs

13

Inte

rface

ImplementationClient

my_table = Table_new(… … …)

Struct Table_t { …data declartions…}

struct Table_T *table_ptr;

struct Table_t *table_ptr;

Client has incomplete

declaration of the struct

© 2010 Noah Mendelsohn

By the way, this is exactly what languages like C++ do

14

class Myclass { int some_method(int a) {…};}

Myclass my_object = new Myclass();

my_object -> some_method(5);

Under the covers, C++ implements this as:

my_object -> some_method(my_object, 5);

© 2010 Noah Mendelsohn

Generalization

© 2010 Noah Mendelsohn

You’ve already seen some generalization

16

int square3() {

return 3*3;}

We don’t do this

int square(int n) {

return n*n;}

We do this!

Generalize over input value

Can we generalize over the type of information?

© 2010 Noah Mendelsohn

We need to generalize over types

17

List_of_students_new(…);List_of_cars_new(…);List_of_bank_stmts_new(…);

We don’t want this

List_new(…);

We want this!

How do we declare the input to List_push()?(after all, its type could be anything)

Can we generalize over the type of information?

© 2010 Noah Mendelsohn

How do we declare List_push?

18

void List_push(List_T list, void *x);

Hanson’s declaration for List_push

struct Car {char *brand; int weight};typedef struct Car Car;Car mycar = {“ford”, 2000};Car *retrieved_car;

mylist = List_list(NULL); /* create empty list */List_push(mylist, &mycar); /* put my car on the list */

© 2010 Noah Mendelsohn

Void * allows us to generalize over types

19

void List_push(List_T list, void *x);

Hanson’s declaration for List_push

The list will remember a pointer to anything.

struct Car {char *brand; int weight};typedef struct Car Car;Car mycar = {“ford”, 2000};Car *retrieved_car;

mylist = List_list(NULL); /* create empty list */List_push(mylist, &mycar); /* put my car on the list */

Any pointer can be passed to a void * parameter

© 2010 Noah Mendelsohn

Void * allows us to generalize over types

20

void List_push(List_T list, void *x);

Hanson’s declaration for List_push

struct Car {char *brand; int weight};typedef struct Car Car;Car mycar = {“ford”, 2000};Car *retrieved_car_p;

mylist = List_list(NULL); /* create empty list */List_push(mylist, &mycar); /* put my car on the list */

List_pop(mylist, &retrieved_car_p); /* get back mycar */

This generalization is known as universal polymorphism

© 2010 Noah Mendelsohn

Void * allows us to generalize over types

21

void List_push(List_T list, void *x);

Hanson’s declaration for List_push

struct Car {char *brand; int weight};typedef struct Car Car;Car mycar = {“ford”, 2000};Car *retrieved_car_p;

mylist = List_list(NULL); /* create empty list */List_push(mylist, &mycar); /* put my car on the list */

List_pop(mylist, &retrieved_car_p); /* get back mycar */

IMPORTANT:Retrieved_car_p is already a pointer. Why do we have to pass the address of retrieved_car_p?

© 2010 Noah Mendelsohn

Generalizing Over Computation

© 2010 Noah Mendelsohn

Why generalize over function?

We’ve already generalized types…sometimes we need different code to work on each type– Classic example: we’re building a sort routine that can sort anything…

– …the rules for sorting different types of things are different

Mapping: do the same operation on each entry in a collection

Providing or overriding behavior in a common implementation– Overriding default output format

– Overriding data source for some input routine

– Etc.

23

© 2010 Noah Mendelsohn

Function pointers in C

We know the code is living in memory

Can we take the address of code? Yes!

24

Syntax

int square(int n) {

return n*n;}

int (*somefunc)(int n);

somefunc = □printf(“3 squared is %d\n”, (*somefunc)(3));

© 2010 Noah Mendelsohn

Be sure you understand why this works!

25

int square(int n) {

return n*n;}

int cube(int n) {

return n*n*n;}

intmain(int argc, char *argv[]){

int (*somefunc)(int n);

somefunc = □printf("3 squared is %d\n", (*somefunc)(3));

somefunc = &cube;printf("3 cubed is %d\n", (*somefunc)(3));

return 0;}

© 2010 Noah Mendelsohn

Be sure you understand why this works!

26

int square(int n) {

return n*n;}

int cube(int n) {

return n*n*n;}

intmain(int argc, char *argv[]){

int (*somefunc)(int n);

somefunc = □printf("3 squared is %d\n", (somefunc)(3));

somefunc = &cube;printf("3 cubed is %d\n", (*somefunc)(3));

return 0;}

The “*” is optional…

…modern versions of C provide it for you if you leave it out.

© 2010 Noah Mendelsohn

Using function pointers

You’ve seen a simple example

We often pass function pointers as arguments to other functions

This allows us to generalize over function

Examples from Hanson:– cmp and hash routines for tables

– apply() functions for mapping

27

© 2010 Noah Mendelsohn

Computing on Collections

© 2010 Noah Mendelsohn

One option: loops

29

/* NOT how Hanson usually does it */tab= Table_new(…):…add some data here..

for (i = 0, i < Table_length(arr) { upcase(Table_getnext(arr, NEXT));}

This is pseudo-code: some details just to show the idea.Hanson doesn’t do it this way anyway.

© 2010 Noah Mendelsohn

The functional (Hanson) way

30

void upcasefunction(void *key, void **value, void *cl) { …can uppercase **value here..}

tab= Table_new(…):…add some data here..Table_map(tab, upcasefunction, ??);

© 2010 Noah Mendelsohn

The functional (Hanson) way

31

void upcasefunction(void *key, void **value, void *cl) { …can uppercase **value here..}

tab= Table_new(…):…add some data here..Table_map(tab, upcasefunction, ??);

The map Table_map function loops calling upcasefunction repeatedly, once for each entry

Passing pointer to function

© 2010 Noah Mendelsohn

The closure: shared data for the mapping

32

void upcasefunction(void *key, void **value, void *cl) { …can uppercase **value here..}struct cl mycl {…shared data here..};

tab= Table_new(…):…add some data here..Table_map(tab, upcasefunction, &mycl);

The data in mycl is passed in from the caller……can be seen and updated in upcasefunction

© 2010 Noah Mendelsohn

Mapping vs loops

Map advantages:– Clean, easy to reason about

– Often less code to write

– Automatically gets the iteration right (e.g. length)

Disadvantages– Less flexible: what if we want to iterate in unusual order?

– Less obvious how to iterate multiple structures at once (there are ways)

– Getting closures right can be tricky

Mapping is a classic functional programming construct

33

© 2010 Noah Mendelsohn

Unboxed DataGeneralizing to Collections of Objects that Aren’t Pointers

© 2010 Noah Mendelsohn

Boxed and unboxed collections

The collections you’ve seen so far are boxed List_push(mylist, &data); /* list stores a pointer */

Problem: we want an array of 1 million characters– A character is 1 byte

– A pointer to a character is 8 bytes

– Even for bigger types, chasing pointers takes time, and allocating memory can be expensive

Unboxed collections: store the actual data, not a pointer!/* array of 1000000 chars */my_array = UArray_new(1000000, sizeof(char));/* set the char at offset 500 to ‘X’ */char *mychar = UArray_at(my_array, 500);*mychar = ‘X’;

35

© 2010 Noah Mendelsohn

Boxed and unboxed collections

The collections you’ve seen so far are boxed List_push(mylist, &data); /* list stores a pointer */

Problem: we want an array of 1 million characters– A character is 1 byte

– A pointer to a character is 8 bytes

– Even for bigger types, chasing pointers takes time, and allocating memory can be expensive

Unboxed collections: store the actual data, not a pointer!/* array of 1000000 chars */my_array = UArray_new(1000000, sizeof(char));/* set the char at offset 500 to ‘X’ */char *mychar = UArray_at(my_array, 500);*mychar = ‘X’;

36

Space for 1000000 characters is allocated in the Hanson array…we could use sizeof(struct SomeBigStruct) and that would work too!

© 2010 Noah Mendelsohn

Boxed and unboxed collections

The collections you’ve seen so far are boxed List_push(mylist, &data); /* list stores a pointer */

Problem: we want an array of 1 million characters– A character is 1 byte

– A pointer to a character is 8 bytes

– Even for bigger types, chasing pointers takes time, and allocating memory can be expensive

Unboxed collections: store the actual data, not a pointer!/* array of 1000000 chars */my_array = UArray_new(1000000, sizeof(char));/* set the char at offset 500 to ‘X’ */char *mychar = UArray_at(my_array, 500);*mychar = ‘X’;

37

Uarray_at returns a pointer directly into the data array that’s inside the Hanson implementation…that’s its contract.