Generic Pointers
Generic Data Structures 1
/************ Implementation ***********/ Stacks typedef struct list_node list; struct list_node { string data; list* next; }; We defined stacks of strings typedef struct stack_header stack; … But, /**************** Interface ****************/ o the code for stacks of ints would be // typedef ______* stack_t; identical except for string changed to int bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; o the code for stacks of any type would be stack_t stack_new() identical except for string changed to this /*@ensures \result != NULL; @*/ type /*@ensures stack_empty(\result); @*/ ; void push(stack_t S, string x) o … /*@requires S != NULL; @*/ /*@ensures !stack_empty(S); @*/ ; string pop(stack_t S) /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; 2
/************ Implementation ***********/ Stacks typedef struct list_node list; struct list_node { string data; list* next; }; Each time we need a stack for a new typedef struct stack_header stack; element type, we need to make a copy … of the stack library /**************** Interface ****************/ // typedef ______* stack_t; This is bad o It’s easy to make a mistake bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; o We need to come up with new names stack_t stack_new() int_stack_t, int_stack_empty , … /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; int_list, int_list_node, is_int_segment , … o If we discover a bug, we need to fix it in void push(stack_t S, string x) /*@requires S != NULL; @*/ every copy of the library /*@ensures !stack_empty(S); @*/ ; same if we discover a better implementation string pop(stack_t S) /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; For a large application, this quickly becomes unmanageable 3
Generic Data Structures Stacks are intrinsecally generic data structures o They work the same way no matter the type of their elements o They do not modify elements they only store them in the data structure and give them back We would like to implement them as a generic library o a single stack implementation that can be used for elements of any type without copying it over and over without a proliferation of function and type names o if we find a bug, there is one place where to fix it if we are told of a better implementation, there is one file to change 4
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; Here’s an idea: list* next; o use a generic type name elem in the library }; o let the client define what elem is typedef struct stack_header stack; … /**************** Interface ****************/ We note the type elem is to be defined // typedef ______* stack_t; by the client in the client interface bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; The client needs to define what elem stack_t stack_new() actually is in the client definition code /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; void push(stack_t S, elem x) /*@requires S != NULL; @*/ /*@ensures !stack_empty(S); @*/ ; elem pop(stack_t S) /******** Client definitions ********/ /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; typedef string elem; 5
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; Pros: list* next; }; A single library for any kind of stack typedef struct stack_header stack; … o If the client needs a stack of ints in a /**************** Interface ****************/ different application, simply define elem as int // typedef ______* stack_t; bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; o If another application stack_t stack_new() requires a different /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; stack type, just define elem appropriately void push(stack_t S, elem x) /*@requires S != NULL; @*/ /*@ensures !stack_empty(S); @*/ ; elem pop(stack_t S) /******** Client definitions ********/ /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; typedef int elem; 6
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; Cons: list* next; }; Client application has to be split into typedef struct stack_header stack; two files … /***** Client definitions *****/ Client definition file /**************** Interface ****************/ typedef string elem; This is mildly // typedef ______* stack_t; Rest of the client application /* Client application */ annoying bool stack_empty(stack_t S) int main() { /*@requires S != NULL; @*/ ; … push … pop … o because } stack_t stack_new() the library needs elem to be defined /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; This must occur before the library the client application needs the types and void push(stack_t S, elem x) /*@requires S != NULL; @*/ functions provided by the library to be defined /*@ensures !stack_empty(S); @*/ ; This must occur after the library elem pop(stack_t S) /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; 7
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; list* next; /***** Client definitions *****/ }; Client definitions file client-stack.c0 typedef string elem; typedef struct stack_header stack; … /* Client application */ App. /**************** Interface ****************/ int main() { file main.c0 … push … pop … // typedef ______* stack_t; } bool stack_empty(stack_t S) Linux Terminal /*@requires S != NULL; @*/ ; # cc0 -d client-stack.c0 stack.c0 main.c0 stack_t stack_new() /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; Library void push(stack_t S, elem x) file stack.c0 /*@requires S != NULL; @*/ /*@ensures !stack_empty(S); @*/ ; This forces an unnatural compilation elem pop(stack_t S) pattern /*@requires S != NULL; @*/ /*@requires !stack_empty(S); @*/ ; This is mildly annoying 8
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; Cons: list* next; }; Client application can contain at most typedef struct stack_header stack; one type of stacks … /**************** Interface ****************/ o no way to have both a stack of strings and // typedef ______* stack_t; a stack of ints in the same application This is a big deal but we can have multiple stacks of ints bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; o because there can be only one definition stack_t stack_new() /*@ensures \result != NULL; @*/ for elem /*@ensures stack_empty(\result); @*/ ; void push(stack_t S, elem x) /***** Client definitions *****/ ? /*@requires S != NULL; @*/ /*@ensures !stack_empty(S); @*/ ; typedef string elem; typedef int elem; The compiler won’t elem pop(stack_t S) know which elem /*@requires S != NULL; @*/ to use when /*@requires !stack_empty(S); @*/ ; Compilation error! 9
/************ Client Interface ***********/ // typedef ______ elem; Generic Stacks -- Take 1 /************ Implementation ***********/ typedef struct list_node list; struct list_node { elem data; Summary list* next; }; typedef struct stack_header stack; Pros: … o A single library for any kind of stacks /**************** Interface ****************/ // typedef ______* stack_t; This is mildly annoying Cons: bool stack_empty(stack_t S) /*@requires S != NULL; @*/ ; o Client application is split into two files stack_t stack_new() Unnatural compilation pattern /*@ensures \result != NULL; @*/ /*@ensures stack_empty(\result); @*/ ; o Client application can contain at most one void push(stack_t S, elem x) /*@requires S != NULL; @*/ type of stacks /*@ensures !stack_empty(S); @*/ ; elem pop(stack_t S) /*@requires S != NULL; @*/ This is a /*@requires !stack_empty(S); @*/ ; big deal 10
Can we do Better? Not in C0 … … but the language C1 extends C0 with a mechanism to address these issues 11
C1 12
The language C1 C1 is an extension of C0 o Every C0 program is a C1 program C1 provides two additional mechanisms o Generic pointers o Function pointers Both help with genericity Right now, we will only examine generic pointers 13
Running C1 Programs C1 programs are compiled with cc0 o but C1-only constructs are only allowed in files with a .c1 extension C0-only code can appear in files with either a .c0 or a .c1 extension Example Linux Terminal # cc0 -d uba.c0 stack.c1 main.c1 File written File with File that may (or may not) purely in C0 C1 code contain C1 constructs The coin interpreter does not currently support C1 constructs o no way to experiment with them in coin 14
Generic Pointers 15
Recommend
More recommend