Download presentation
Presentation is loading. Please wait.
Published byAldous Stanley Modified over 9 years ago
1
More on Abstract Data Types Noah Mendelsohn Tufts University Email: noah@cs.tufts.edunoah@cs.tufts.edu Web: http://www.cs.tufts.edu/~noah COMP 40: Machine Structure and Assembly Language Programming (Spring 2014)
2
© 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
3
© 2010 Noah Mendelsohn Quick Review
4
© 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…
5
© 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”
6
© 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 IdeasCOMP 11 Big Ideas 2 Ken Thompson, co-inventor of Unix – The Unix PhilosophyThe Unix Philosophy
7
© 2010 Noah Mendelsohn Interfaces 7 Interface Implementation Client E.g. your fgroups program E.g. implementation of Hanson Table_T E.g. methods in Hanson table.h
8
© 2010 Noah Mendelsohn Interfaces 8 Interface Implementation Client Many different programs can re-use the interface and the implementation! The implementation chooses a representation … NOT visible to the client
9
© 2010 Noah Mendelsohn Interfaces 9 Interface Implementation Client E.g. your fgroups program E.g. implementation of Hanson 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
10
© 2010 Noah Mendelsohn Client doesn’t know secret implementation 10 Interface Implementation Client my_table = Table_new(… … …) Struct Table_t { …data declartions… } struct Table_T *table_ptr; void *table_ptr;
11
© 2010 Noah Mendelsohn Client doesn’t know secret implementation 11 Interface Implementation Client my_table = Table_new(… … …) Struct Table_t { …data declartions… } struct Table_T *table_ptr; void *table_ptr; Note: This declaration would be in the publicly used table.h!
12
© 2010 Noah Mendelsohn Client doesn’t know secret implementation 12 Interface Implementation Client 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)
13
© 2010 Noah Mendelsohn Hanson does this with incomplete structs 13 Interface Implementation Client 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
14
© 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);
15
© 2010 Noah Mendelsohn Generalization
16
© 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?
17
© 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?
18
© 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 */
19
© 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
20
© 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
21
© 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?
22
© 2010 Noah Mendelsohn Generalizing Over Computation
23
© 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
24
© 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));
25
© 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; } int main(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; }
26
© 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; } int main(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.
27
© 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
28
© 2010 Noah Mendelsohn Computing on Collections
29
© 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.
30
© 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, ??);
31
© 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
32
© 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
33
© 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
34
© 2010 Noah Mendelsohn Unboxed Data Generalizing to Collections of Objects that Aren’t Pointers
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’; 35
36
© 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!
37
© 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.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.