Index: doc/theses/aaron_moss_PhD/phd/code/bespoke-generic.c
===================================================================
--- doc/theses/aaron_moss_PhD/phd/code/bespoke-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
+++ doc/theses/aaron_moss_PhD/phd/code/bespoke-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+struct int_list { int value; struct int_list* next; };
+
+void int_list_insert( struct int_list** ls, int x ) {
+	struct int_list* node = malloc(sizeof(struct int_list));
+	node->value = x; node->next = *ls;
+	*ls = node;
+}
+
+int int_list_head( const struct int_list* ls ) { return ls->value; }
+
+// all code must be duplicated for every generic instantiation
+
+struct string_list { const char* value; struct string_list* next; };
+
+void string_list_insert( struct string_list** ls, const char* x ) {
+	struct string_list* node = malloc(sizeof(struct string_list));
+	node->value = x; node->next = *ls;
+	*ls = node;
+}
+
+const char* string_list_head( const struct string_list* ls )
+	{ return ls->value; }
+
+// use is efficient and idiomatic
+
+int main() {
+	struct int_list* il = NULL;
+	int_list_insert( &il, 42 );
+	printf("%d\n", int_list_head(il));
+	
+	struct string_list* sl = NULL;
+	string_list_insert( &sl, "hello" );
+	printf("%s\n", string_list_head(sl) );
+}
Index: doc/theses/aaron_moss_PhD/phd/code/macro-generic.c
===================================================================
--- doc/theses/aaron_moss_PhD/phd/code/macro-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
+++ doc/theses/aaron_moss_PhD/phd/code/macro-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+// code is nested in macros
+
+#define list(N) N ## _list
+
+#define list_insert(N) N ## _list_insert
+
+#define list_head(N) N ## _list_head
+
+#define define_list(N, T) \
+	struct list(N) { T value; struct list(N)* next; }; \
+	\
+	void list_insert(N)( struct list(N)** ls, T x ) { \
+		struct list(N)* node = malloc(sizeof(struct list(N))); \
+		node->value = x; node->next = *ls; \
+		*ls = node; \
+	} \
+	\
+	T list_head(N)( const struct list(N)* ls ) { return ls->value; }
+
+define_list(int, int);  // defines int_list
+define_list(string, const char*);  // defines string_list
+
+// use is efficient, but syntactically idiosyncratic
+
+int main() {
+	struct list(int)* il = NULL;
+	list_insert(int)( &il, 42 );
+	printf("%d\n", list_head(int)(il));
+	
+	struct list(string)* sl = NULL;
+	list_insert(string)( &sl, "hello" );
+	printf("%s\n", list_head(string)(sl) );
+}
Index: doc/theses/aaron_moss_PhD/phd/code/void-generic.c
===================================================================
--- doc/theses/aaron_moss_PhD/phd/code/void-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
+++ doc/theses/aaron_moss_PhD/phd/code/void-generic.c	(revision 4075228f1dad43acaa6f29142f46e66e9920b4f1)
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+// single code implementation
+
+struct list { void* value; struct list* next; };
+
+// internal memory management requires helper functions
+
+void list_insert( struct list** ls, void* x, void* (*copy)(void*) ) {
+	struct list* node = malloc(sizeof(struct list));
+	node->value = copy(x); node->next = *ls;
+	*ls = node;
+}
+
+void* list_head( const struct list* ls ) { return ls->value; }
+
+// helpers duplicated per type
+
+void* int_copy(void* x) {
+	int* n = malloc(sizeof(int));
+	*n = *(int*)x;
+	return n;
+}
+
+void* string_copy(void* x) { return strdup((const char*)x); }
+
+int main() {
+	struct list* il = NULL;
+	int i = 42;
+	list_insert( &il, &i, int_copy );
+	printf("%d\n", *(int*)list_head(il));  // unsafe type cast
+	
+	struct list* sl = NULL;
+	list_insert( &sl, "hello", string_copy );
+	printf("%s\n", (char*)list_head(sl) );
+}
