Abstraction, Modularity, Interfaces and Pointers
Original slides by Noah Mendelsohn, including content from Mark Sheldon, Noah Daniels, Norman Ramsey
COMP 40: Machine Structure and
Assembly Language Programming
© 2010 Noah Mendelsohn
We will weave together a story about
Abstraction, modularity, reuse, clean interfaces, information hiding
C Language Pointers
Is it obvious these are related at all?
© 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
© 2010 Noah Mendelsohn
Collections are especially interesting
Arrays of Integer temperature measurements
Queues of Students waiting to register for classes
Sorted lists of Bank statements
Etc.
6
© 2010 Noah Mendelsohn7
Today we will focus on good ways of modeling Abstract Data Types like lists, sets, queues, etc.
Doing that, we’ll learn a lot about programming with pointers and types in C
© 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
– This makes them more modular: why?
Generalization– When practical, each module or service should be as generally useful as
possible
8
1 Prof. Mark Sheldon – COMP 11 Big Ideas 2 Ken Thompson, co-inventor of Unix – The Unix Philosophy
© 2010 Noah Mendelsohn
What are the benefits of software like this?
Easier to use
Easier to reuse
Easier to replace
Easier to reason about correctness
Easer to test
Easier to maintain
Etc., etc.
9
© 2010 Noah Mendelsohn
Interfaces (Recall picture from Comp 11)
11
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
12
Inte
rface
ImplementationClient
Many different programs can re-use the interface and the implementation!
© 2010 Noah Mendelsohn
Interfaces
13
Inte
rface
ImplementationClient
The implementation chooses a representation … NOT visible to the client
© 2010 Noah Mendelsohn
Interfaces
14
Inte
rface
ImplementationClient
We can build different implementations without the client knowing
Why reimplement?
One might be small, one might be fast, etc.
Bug fixes
We might figure out a better way next year
© 2010 Noah Mendelsohn
Interfaces
16
Inte
rface
ImplementationClient
To make this work we must…
…hide details of the implementation from the client!
© 2010 Noah Mendelsohn
Interfaces
17
Inte
rface
ImplementationClient
To make this work we must…
…hide details of the client from the implementation!
© 2010 Noah Mendelsohn
Interfaces
18
Inte
rface
ImplementationClient
Build interfaces that cleanly model the service or abstract data…
© 2010 Noah Mendelsohn19
In your COMP 40 design documents, we expect you to carefully observe these distinctions…
…your description of an interface should never mention implementation details
…your description of use of an interface should never mention implementation details.
© 2010 Noah Mendelsohn
Most pointer declarations include type of the referent
21
#include <stdio.h>#include <stdlib.h>
intmain(int argc, char *argv[]){
(void)argc;(void)argv;
int x = 3;int y;
int *ptr; ptr = &x;
y = *ptr;
printf("y = %d\n", y);
exit(EXIT_SUCCESS);}
Pointer to an integer
© 2010 Noah Mendelsohn
Void pointers are to unknown type
23
#include <stdio.h>#include <stdlib.h>
intmain(int argc, char *argv[]){
(void)argc;(void)argv;
int x = 3;int y;
void *ptr; ptr = &x;
y = *ptr;
printf("y = %d\n", y);
exit(EXIT_SUCCESS);}
Compile error!!
Can’t assign value of unknown type (*ptr) to integer y.
void *
Compiler knows it’s a pointer.
Compiler does not know what type it points to.
© 2010 Noah Mendelsohn
But we can tell the compiler the type
24
#include <stdio.h>#include <stdlib.h>
intmain(int argc, char *argv[]){
(void)argc;(void)argv;
int x = 3;int y;
void *ptr; ptr = &x;
y = *((int *)ptr);
printf("y = %d\n", y);
exit(EXIT_SUCCESS);}
FIXED!
We can use a cast (in this case
((int *)ptr)
to tell the compiler the type it should assume
© 2010 Noah Mendelsohn
Void pointers let us do some very important things!
Make our code more general – work with any type of data
Keep secrets
25
But why would we want to keep secrets?
© 2010 Noah Mendelsohn
Interfaces
26
Inte
rface
ImplementationClient
E.g. your fgroups program
E.g. implementation ofHanson Table_T
E.g. methods in Hanson table.h
My client isn’t supposed to see internals of Hanson’s table, but Hanson needs to give us something….what can we use?
© 2010 Noah Mendelsohn
Interfaces
27
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
Using void * pointers
28
/* Declare the type Table_t to be a (void *) */typedef void *Table_t;
/* Define Table_new to return one of those (void *) */Table_t Table_new(… … … …);
This is a pretty good solution:
• Client can’t see details of what’s in Hanson’s structure• When Hanson gets the pointer back, he can assign it to
a Table_T and use it
© 2010 Noah Mendelsohn
Client doesn’t know secret implementation
29
Inte
rface
ImplementationClient
my_table = Table_new(… … …)
Struct Table_t { …data declartions…}
struct Table_T *table_ptr;
void *table_ptr;
© 2010 Noah Mendelsohn
Using void * pointers
30
/* Declare the type Table_t to be a (void *) */typedef void *Table_t;
/* Define Table_new to return a (void *) */Table_t Table_new(… … … …);
This is a pretty good solution:
• Client can’t see details of what’s in Hanson’s structure• When Hanson gets the pointer back, he can assign it to
a Table_T and use it• But it doesn’t catch this mistake in the client…
myTable = List_new(…);Table_put(myTable, … … …)
© 2010 Noah Mendelsohn
We can do better with incomplete structures
31
typedef struct Table_T *Table_t;
Tricky…we’re exposing the structure’s name, but not it’s contents…C calls this an incomplete structure.
You cannot declare a variable with an incomplete type.
You can declare a variable that’s a pointer to an incomplete type!
Declare the type Table_t to be a pointer to a struct whose contents are unspecified:
© 2010 Noah Mendelsohn
We can do better with incomplete structures
32
typedef struct Table_T *Table_t;
/* Table_new returns ptr to incomplete struct */Table_t Table_new(… … … …);
Tricky…we’re exposing the structure’s name, but not it’s contents…C calls this an incomplete structure.
© 2010 Noah Mendelsohn
Client doesn’t know secret implementation
33
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
We can do better with incomplete structures
34
typedef struct Table_T *Table_t;
Table_t Table_new(… … … …);
This is a better solution:
• Client can’t see details of what’s in Hanson’s structure• When Hanson gets the pointer back, it just works• It does catch this mistake…you should figure out why!
myTable = List_new(…);Table_put(myTable, … … …)
© 2010 Noah Mendelsohn
You’ve already seen some generalization
36
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
37
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
Void * allows us to generalize over types
38
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;List_T mylist = List_list(NULL); Car *retrieved_car;Car mycar = {"ford", 2000};
mylist = List_push(mylist, &mycar); mylist = List_pop(mylist, (void **)&retrieved_car);
List_free(&mylist);
Any pointer can be passed to a pointer-to-void parameter
© 2010 Noah Mendelsohn
Void * allows us to generalize over types
39
void List_push(List_T list, void *x);
Hanson’s declaration for List_push
struct Car {char *brand; int weight;}; typedef struct Car Car;List_T mylist = List_list(NULL); Car *retrieved_car;Car mycar = {"ford", 2000};
mylist = List_push(mylist, &mycar); mylist = List_pop(mylist, (void **)&retrieved_car);
List_free(&mylist);
IMPORTANT:Retrieved_car_p is already a pointer. Why do we have to pass the address of retrieved_car_p?
© 2010 Noah Mendelsohn
Void * allows us to generalize over types
40
void List_push(List_T list, void *x);
Hanson’s declaration for List_push
struct Car {char *brand; int weight;}; typedef struct Car Car;List_T mylist = List_list(NULL); Car *retrieved_car;Car mycar = {"ford", 2000};
mylist = List_push(mylist, &mycar); mylist = List_pop(mylist, (void **)&retrieved_car);
List_free(&mylist);
This generalization is known as universal polymorphism