Index: doc/generic_types/evaluation/Makefile
===================================================================
--- doc/generic_types/evaluation/Makefile	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/Makefile	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,22 @@
+CFA=cfa
+
+# %.o : %.cf
+#	$(CFA) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+
+cfa-stack.o: cfa-stack.c cfa-stack.h
+	$(CFA) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+
+c-bench: c-bench.c bench.h c-stack.o
+	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< c-stack.o
+
+cpp-bench: cpp-bench.cpp bench.h cpp-stack.h
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
+
+cfa-bench: cfa-bench.c bench.h cfa-stack.o
+	$(CFA) $(CFLAGS) $(CPPFLAGS) -o $@ $< cfa-stack.o
+
+clean:
+	-rm *.o
+	-rm c-bench
+	-rm cpp-bench
+	-rm cfa-bench
Index: doc/generic_types/evaluation/bench.h
===================================================================
--- doc/generic_types/evaluation/bench.h	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/bench.h	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <time.h>
+
+#define N 200000000
+
+long ms_between(clock_t start, clock_t end) {
+	return (end - start) / (CLOCKS_PER_SEC / 1000);
+}
+
+#define TIMED(name, code) { \
+	clock_t start, end; \
+	start = clock(); \
+	code \
+	end = clock(); \
+	printf("%s:\t%7ld ms\n", name, ms_between(start, end)); \
+}
+
+#define REPEAT_TIMED(name, code) TIMED( name, for (int i = 0; i < N; ++i) { code } )
Index: doc/generic_types/evaluation/c-bench.c
===================================================================
--- doc/generic_types/evaluation/c-bench.c	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/c-bench.c	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include "bench.h"
+#include "c-stack.h"
+
+int main(int argc, char** argv) {
+	srand(20171025);
+
+	struct stack s = new_stack();
+
+	REPEAT_TIMED( "push_int",
+		int* x = malloc(sizeof(int));
+		*x = rand();
+		push_stack(&s, x);
+	)
+
+	clear_stack(&s);
+}
Index: doc/generic_types/evaluation/c-stack.c
===================================================================
--- doc/generic_types/evaluation/c-stack.c	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/c-stack.c	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include "c-stack.h"
+
+struct stack_node {
+	void* value;
+	struct stack_node* next;
+};
+
+struct stack new_stack() {
+	return (struct stack){ NULL };
+}
+
+void clear_stack(struct stack* s) {
+	struct stack_node* next = s->head;
+	while ( next ) {
+		struct stack_node* crnt = next;
+		next = crnt->next;
+		free(crnt->value);
+		free(crnt);
+	}
+}
+
+_Bool stack_empty(const struct stack* s) {
+	return s->head == NULL;
+}
+
+void push_stack(struct stack* s, void* value) {
+	struct stack_node* n = malloc(sizeof(struct stack_node));
+	*n = (struct stack_node){ value, s->head };
+	s->head = n;
+}
+
+void* pop_stack(struct stack* s) {
+	struct stack_node* n = s->head;
+	s->head = n->next;
+	void* x = n->value;
+	free(n);
+	return x;
+}
Index: doc/generic_types/evaluation/c-stack.h
===================================================================
--- doc/generic_types/evaluation/c-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/c-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,15 @@
+struct stack_node;
+
+struct stack {
+	struct stack_node* head;
+};
+
+struct stack new_stack();
+
+void clear_stack(struct stack* s);
+
+_Bool stack_empty(const struct stack* s);
+
+void push_stack(struct stack* s, void* value);
+
+void* pop_stack(struct stack* s);
Index: doc/generic_types/evaluation/cfa-bench.c
===================================================================
--- doc/generic_types/evaluation/cfa-bench.c	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/cfa-bench.c	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include "bench.h"
+#include "cfa-stack.h"
+
+int main(int argc, char** argv) {
+	srand(20171025);
+
+	stack(int) s;
+
+	REPEAT_TIMED( "push_int",
+		push( &s, rand() );
+	)
+}
Index: doc/generic_types/evaluation/cfa-stack.c
===================================================================
--- doc/generic_types/evaluation/cfa-stack.c	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/cfa-stack.c	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,36 @@
+#include <stdlib>
+#include "cfa-stack.h"
+
+forall(otype T) struct stack_node {
+	T value;
+	stack_node(T)* next;
+};
+
+forall(otype T) void ?{}(stack(T)* s) {
+	?{}( s->head, 0 );
+}
+
+forall(otype T) void ^?{}(stack(T)* s) {
+	stack_node(T)* next = s->head;
+	while ( next ) {
+		stack_node(T)* crnt = next;
+		next = crnt->next;
+		delete(crnt);
+	}
+}
+
+forall(otype T) _Bool empty(const stack(T)* s) {
+	return s->head == 0;
+}
+
+forall(otype T) void push(stack(T)* s, T value) {
+	s->head = new( value, s->head );
+}
+
+forall(otype T) T pop(stack(T)* s) {
+	stack_node(T)* n = s->head;
+	s->head = n->next;
+	T x = n->value;
+	delete(n);
+	return x;
+}
Index: doc/generic_types/evaluation/cfa-stack.h
===================================================================
--- doc/generic_types/evaluation/cfa-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/cfa-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,15 @@
+forall(otype T) struct stack_node;
+
+forall(otype T) struct stack {
+	stack_node(T)* head;
+};
+
+forall(otype T) void ?{}(stack(T)* s);
+
+forall(otype T) void ^?{}(stack(T)* s);
+
+forall(otype T) _Bool empty(const stack(T)* s);
+
+forall(otype T) void push(stack(T)* s, T value);
+
+forall(otype T) T pop(stack(T)* s);
Index: doc/generic_types/evaluation/cpp-bench.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-bench.cpp	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/cpp-bench.cpp	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include "bench.h"
+#include "cpp-stack.h"
+
+int main(int argc, char** argv) {
+	srand(20171025);
+
+	stack<int> s;
+
+	REPEAT_TIMED( "push_int",
+		s.push( rand() );
+	)
+}
Index: doc/generic_types/evaluation/cpp-stack.h
===================================================================
--- doc/generic_types/evaluation/cpp-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
+++ doc/generic_types/evaluation/cpp-stack.h	(revision 309be815f9581d269c57765858cb936357aef479)
@@ -0,0 +1,40 @@
+#include <utility>
+
+template<typename T> class stack {
+	struct node {
+		T value;
+		node* next;
+
+		node( T&& v, node* n ) : value(std::move(v)), next(n) {}
+	};
+	
+	node* head;
+
+public:
+	stack() : head(nullptr) {}
+
+	~stack() {
+		node* next = head;
+		while ( next ) {
+			node* crnt = next;
+			next = crnt->next;
+			delete crnt;
+		}
+	}
+
+	bool empty() const {
+		return head == nullptr;
+	}
+
+	void push(T&& value) {
+		head = new node{ std::move(value), head };
+	}
+
+	T pop() {
+		node* n = head;
+		head = n->next;
+		T x = std::move(n->value);
+		delete n;
+		return x;
+	}
+};
