Index: doc/generic_types/evaluation/Makefile
===================================================================
--- doc/generic_types/evaluation/Makefile	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/Makefile	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -34,7 +34,7 @@
 
 CFILES = c-bench.c bench.h $(COBJS:.o=.h) $(COBJS:.o=.c)
-CPPFILES = cpp-bench.cpp bench.hpp cpp-stack.hpp cpp-print.hpp
+CPPFILES = cpp-bench.cpp bench.hpp cpp-stack.hpp cpp-pair.hpp cpp-print.hpp
 CPPVFILES = cpp-vbench.cpp bench.hpp object.hpp $(CPPVOBJS:.o=.hpp) $(CPPVOBJS:.o=.cpp) cpp-vprint.hpp
-CFAFILES = cfa-bench.c bench.h cfa-stack.h cfa-print.h cfa-stack.c cfa-print.c
+CFAFILES = cfa-bench.c bench.h $(CFAOBJS:.o=.h) $(CFAOBJS:.o=.c)
 
 c-bench: c-bench.c c-bench.d $(COBJS)
Index: doc/generic_types/evaluation/bench.h
===================================================================
--- doc/generic_types/evaluation/bench.h	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/bench.h	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -13,4 +13,3 @@
 	printf("%s:\t%8ld ms\n", name, ms_between(_start, _end)); \
 }
-#define REPEAT_N_TIMED(name, n, code) TIMED( name, for (int _i = 0; _i < n; ++_i) { code } )
-#define REPEAT_TIMED(name, code) REPEAT_N_TIMED(name, N, code)
+#define REPEAT_TIMED(name, n, code) TIMED( name, for (int _i = 0; _i < n; ++_i) { code } )
Index: doc/generic_types/evaluation/bench.hpp
===================================================================
--- doc/generic_types/evaluation/bench.hpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/bench.hpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -15,4 +15,3 @@
 		<< std::setw(0) << " ms" << std::endl; \
 }
-#define REPEAT_N_TIMED(name, n, code) TIMED( name, for (int _i = 0; _i < n; ++_i) { code } )
-#define REPEAT_TIMED(name, code) REPEAT_N_TIMED(name, N, code)
+#define REPEAT_TIMED(name, n, 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 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/c-bench.c	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -34,43 +34,40 @@
 }
 
-int cmp_char( const void* a, const void* b ) {
-	return *(const char*)a == *(const char*)b ? 0 : *(const char*)a < *(const char*)b ? -1 : 1; /***/
+int cmp_char( const void* a, const void* b ) { /***/
+	return *(const char*)a == *(const char*)b ? 0 : *(const char*)a < *(const char*)b ? -1 : 1;
 }
 
 int main(int argc, char** argv) {
-	FILE* out = fopen("c-out.txt", "w");
-	int max = 0;
-	struct stack s = new_stack(), t;
-	REPEAT_TIMED( "push_int", push_stack(&s, new_int( _i )); )
-	TIMED( "copy_int", 	copy_stack(&t, &s, copy_int); /***/ )
-	TIMED( "clear_int", clear_stack(&s, free); /***/ )
-	REPEAT_TIMED( "pop_int", 
-		int* x = pop_stack(&t); /***/
-		if ( *x > max ) { max = *x; }
-		free(x); )
-	REPEAT_N_TIMED( "print_int", N/2, print( out, "dsds", _i, ":", _i, "\n" ); /***/ )
+	FILE * out = fopen("c-out.txt", "w");
+	int maxi = 0, vali = 42;
+	struct stack si = new_stack(), ti;
 
-	struct pair* max2 = new_pair( new_bool(0), new_char('\0') );
-	struct stack s2 = new_stack(), t2;
+	REPEAT_TIMED( "push_int", N, push_stack( &si, new_int( vali ) ); )
+	TIMED( "copy_int", 	copy_stack( &ti, &si, copy_int ); /***/ )
+	TIMED( "clear_int", clear_stack( &si, free ); /***/ )
+	REPEAT_TIMED( "pop_int", N, 
+		int* xi = pop_stack( &ti );
+		if ( *xi > maxi ) { maxi = *xi; }
+		free(xi); )
+	REPEAT_TIMED( "print_int", N/2, print( out, "dsds", vali, ":", vali, "\n" ); /***/ )
 
-	REPEAT_TIMED( "push_bool_char", 
-		push_stack(&s2, new_pair( new_bool( _i & 0x1 ), new_char( _i & 0x7F ) )); )
-	TIMED( "copy_bool_char", copy_stack(&t2, &s2, copy_pair_bool_char); /***/ )
-	TIMED( "clear_bool_char", clear_stack(&s2, free_pair_bool_char); /***/ )
-	REPEAT_TIMED( "pop_bool_char", 
-		struct pair* x = pop_stack(&t2); /***/
-		if ( cmp_pair( x, max2, cmp_bool, cmp_char ) > 0 ) { /***/
-			free_pair_bool_char( max2 ); /***/
-			max2 = x;
+	struct pair * maxp = new_pair( new_bool(0), new_char('\0') ),
+		* valp = new_pair( new_bool(1), new_char('a') );
+	struct stack sp = new_stack(), tp;
+
+	REPEAT_TIMED( "push_pair", N, push_stack( &sp, copy_pair_bool_char( valp ) ); )
+	TIMED( "copy_pair", copy_stack( &tp, &sp, copy_pair_bool_char ); /***/ )
+	TIMED( "clear_pair", clear_stack( &sp, free_pair_bool_char ); /***/ )
+	REPEAT_TIMED( "pop_pair", N, 
+		struct pair * xp = pop_stack( &tp );
+		if ( cmp_pair( xp, maxp, cmp_bool, cmp_char /***/ ) > 0 ) {
+			free_pair_bool_char( maxp ); /***/
+			maxp = xp;
 		} else {
-			free_pair_bool_char( x ); /***/
+			free_pair_bool_char( xp ); /***/
 		} )
-	REPEAT_N_TIMED( "print_pair", N/2, 
-		struct pair p1 = ((struct pair){ new_bool(rand() & 0x1), new_char(rand() & 0x7F) }); /***/
-		struct pair p2 = ((struct pair){ new_bool(rand() & 0x1), new_char(rand() & 0x7F) }); /***/
-		print( out, "pbcspbcs", p1, ":", p2, "\n" ); /***/
-		free(p1.first); free(p1.second); /***/
-		free(p2.first); free(p2.second); /***/ )
-	free_pair_bool_char( max2 ); /***/
+	REPEAT_TIMED( "print_pair", N/2, print( out, "pbcspbcs", *valp, ":", *valp, "\n" ); /***/ )
+	free_pair_bool_char( maxp ); /***/
+	free_pair_bool_char( valp ); /***/
 	fclose(out);
 }
Index: doc/generic_types/evaluation/cfa-bench.c
===================================================================
--- doc/generic_types/evaluation/cfa-bench.c	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cfa-bench.c	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,34 +1,32 @@
 #include <stdlib>
 #include <stdio.h>
-#include "pair"
 #include "bench.h"
 #include "cfa-stack.h"
+#include "cfa-pair.h"
 #include "cfa-print.h"
 
 int main( int argc, char *argv[] ) {
 	FILE * out = fopen( "cfa-out.txt", "w" );
-	int max = 0;
-	stack(int) s, t;
+	int maxi = 0, vali = 42;
+	stack(int) si, ti;
 
-	REPEAT_TIMED( "push_int", push( &s, _i ); )
-	TIMED( "copy_int", t = s; )
-	TIMED( "clear_int", clear( &s ); )
-	REPEAT_TIMED( "pop_int", 
-		int x = pop(&t); 
-		if ( x > max ) { max = x; } )
-	REPEAT_TIMED( "print_int", print( out, _i, ":", _i, "\n" ); )
+	REPEAT_TIMED( "push_int", N, push( &si, vali ); )
+	TIMED( "copy_int", ti = si; )
+	TIMED( "clear_int", clear( &si ); )
+	REPEAT_TIMED( "pop_int", N, 
+		int xi = pop( &ti ); 
+		if ( xi > maxi ) { maxi = xi; } )
+	REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); )
 
-	stack(pair(_Bool, char)) s1, t1;
-	pair(_Bool, char) max = { (_Bool)0, '\0' };
+	pair(_Bool, char) maxp = { (_Bool)0, '\0' }, valp = { (_Bool)1, 'a' };
+	stack(pair(_Bool, char)) sp, tp;
 
-	REPEAT_TIMED( "push_pair", push( &s1, (pair(_Bool, char)){ _i & 1, _i &0x7F } ); )
-	TIMED( "copy_pair", t1 = s1; )
-	TIMED( "clear_pair", clear( &s1 ); )
-	REPEAT_TIMED( "pop_pair",
-		pair(_Bool, char) x = pop(&t1); 
-		if ( x > max ) { max = x; } )
-	REPEAT_TIMED( "print_pair",
-		 print( out, (pair(_Bool, char)){  _i & 1, _i &0x7F }, ":", 
-		 	(pair(_Bool, char)){  _i & 1, _i &0x7F }, "\n" ); )
+	REPEAT_TIMED( "push_pair", N, push( &sp, valp ); )
+	TIMED( "copy_pair", tp = sp; )
+	TIMED( "clear_pair", clear( &sp ); )
+	REPEAT_TIMED( "pop_pair", N, 
+		pair(_Bool, char) xp = pop( &tp ); 
+		if ( xp > maxp ) { maxp = xp; } )
+	REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); )
 	fclose(out);
 }
Index: doc/generic_types/evaluation/cfa-pair.c
===================================================================
--- doc/generic_types/evaluation/cfa-pair.c	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cfa-pair.c	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,3 +1,3 @@
-#include "pair"
+#include "cfa-pair.h"
 
 forall(otype R, otype S 
Index: doc/generic_types/evaluation/cfa-pair.h
===================================================================
--- doc/generic_types/evaluation/cfa-pair.h	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
+++ doc/generic_types/evaluation/cfa-pair.h	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -0,0 +1,28 @@
+#pragma once
+
+forall(otype R, otype S) struct pair {
+	R first;
+	S second;
+};
+
+forall(otype R, otype S 
+	| { int ?==?(R, R); int ?<?(R, R); int ?<?(S, S); })
+int ?<?(pair(R, S) p, pair(R, S) q);
+
+forall(otype R, otype S 
+	| { int ?==?(R, R); int ?<?(R, R); int ?<=?(S, S); })
+int ?<=?(pair(R, S) p, pair(R, S) q);
+
+forall(otype R, otype S | { int ?==?(R, R); int ?==?(S, S); })
+int ?==?(pair(R, S) p, pair(R, S) q);
+
+forall(otype R, otype S | { int ?!=?(R, R); int ?!=?(S, S); })
+int ?!=?(pair(R, S) p, pair(R, S) q);
+
+forall(otype R, otype S 
+	| { int ?==?(R, R); int ?>?(R, R); int ?>?(S, S); })
+int ?>?(pair(R, S) p, pair(R, S) q);
+
+forall(otype R, otype S 
+	| { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); })
+int ?>=?(pair(R, S) p, pair(R, S) q);
Index: doc/generic_types/evaluation/cfa-print.c
===================================================================
--- doc/generic_types/evaluation/cfa-print.c	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cfa-print.c	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,4 +1,4 @@
 #include <stdio.h>
-#include "pair"
+#include "cfa-pair.h"
 #include "cfa-print.h"
 
Index: doc/generic_types/evaluation/cfa-print.h
===================================================================
--- doc/generic_types/evaluation/cfa-print.h	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cfa-print.h	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,5 +1,5 @@
 #pragma once
 #include <stdio.h>
-#include "pair"
+#include "cfa-pair.h"
 
 forall(otype T, ttype Params | { void print(FILE*, T); void print(FILE*, Params); })
Index: doc/generic_types/evaluation/cpp-bench.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-bench.cpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-bench.cpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,31 +1,27 @@
 #include <algorithm>
 #include <fstream>
-#include <utility>
 #include "bench.hpp"
 #include "cpp-stack.hpp"
+#include "cpp-pair.hpp"
 #include "cpp-print.hpp"
 
 int main(int argc, char** argv) {
 	std::ofstream out{"cpp-out.txt"};
-	int max = 0;
-	stack<int> s, t;
+	int maxi = 0, vali = 42;
+	stack<int> si, ti;
 	
-	REPEAT_TIMED( "push_int", s.push( int{_i} ); )
-	TIMED( "copy_int", t = s; )
-	TIMED( "clear_int", s.clear(); )
-	REPEAT_TIMED( "pop_int", max = std::max( max, t.pop() ); )
-	print( out, max, "\n" );
-	REPEAT_N_TIMED( "print_int", N/2, print( out, _i, ":", _i, "\n" ); )
+	REPEAT_TIMED( "push_int", N, si.push( vali ); )
+	TIMED( "copy_int", ti = si; )
+	TIMED( "clear_int", si.clear(); )
+	REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop() ); )
+	REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); )
 
-	std::pair<bool, char> max1 = { false, '\0' };
-	stack<std::pair<bool, char>> s1, t1;
+	pair<bool, char> maxp = { false, '\0' }, valp = { true, 'a' };
+	stack<pair<bool, char>> sp, tp;
 	
-	REPEAT_TIMED( "push_bool_char", s1.push( std::pair<bool, char>{ _i & 0x1, _i & 0x7F } ); )
-	TIMED( "copy_bool_char", t1 = s1; )
-	TIMED( "clear_bool_char", s1.clear(); )
-	REPEAT_TIMED( "pop_bool_char", max1 = std::max( max1, t1.pop() ); )
-	print( out, max1, "\n" );
-	REPEAT_N_TIMED( "print_pair", N/2, 
-		print( out, std::pair<bool, char>{ _i & 0x1, _i & 0x7F }, ":",
-				std::pair<bool, char>{ _i & 0x1, _i & 0x7F }, "\n" ); )
+	REPEAT_TIMED( "push_pair", N, sp.push( valp ); )
+	TIMED( "copy_pair", tp = sp; )
+	TIMED( "clear_pair", sp.clear(); )
+	REPEAT_TIMED( "pop_pair", N, maxp = std::max( maxp, tp.pop() ); )
+	REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); )
 }
Index: doc/generic_types/evaluation/cpp-print.hpp
===================================================================
--- doc/generic_types/evaluation/cpp-print.hpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-print.hpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -2,5 +2,5 @@
 #include <iomanip>
 #include <iostream>
-#include <utility>
+#include "cpp-pair.hpp"
 
 template<typename T> void print(std::ostream& out, const T& x) { out << x; }
@@ -14,5 +14,5 @@
 
 template<typename R, typename S> 
-std::ostream& operator<< (std::ostream& out, const std::pair<R, S>& x) {
+std::ostream& operator<< (std::ostream& out, const pair<R, S>& x) {
 	out << "[";
 	print(out, x.first);
Index: doc/generic_types/evaluation/cpp-stack.hpp
===================================================================
--- doc/generic_types/evaluation/cpp-stack.hpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-stack.hpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -7,6 +7,5 @@
 		node* next;
 
-		node( T& v ) : value(v), next(nullptr) {}
-		node( T&& v, node* n ) : value(std::move(v)), next(n) {}
+		node( const T& v, node* n = nullptr ) : value(v), next(n) {}
 	};
 	node* head;
@@ -54,5 +53,5 @@
 	bool empty() const { return head == nullptr; }
 
-	void push(T&& value) { head = new node{ std::move(value), head };  /***/ }
+	void push(const T& value) { head = new node{ value, head };  /***/ }
 
 	T pop() {
Index: doc/generic_types/evaluation/cpp-vbench.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-vbench.cpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-vbench.cpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -8,28 +8,23 @@
 int main(int argc, char** argv) {
 	std::ofstream out{"cpp-vout.txt"};
-	integer max{ 0 };
-	stack s, t;
+	integer maxi{ 0 }, vali{ 42 };
+	stack si, ti;
 	
-	REPEAT_TIMED( "push_int", s.push( make<integer>( _i ) ); )
-	TIMED( "copy_int", t = s; )
-	TIMED( "clear_int", s.clear(); )
-	REPEAT_TIMED( "pop_int", max = std::max( max, t.pop()->as<integer>() ); /***/ )
-	print( out, max, c_string{"\n"} );
-	REPEAT_N_TIMED( "print_int", N/2, 
-		print( out, integer{_i}, c_string{":"}, integer{_i}, c_string{"\n"} ); )
+	REPEAT_TIMED( "push_int", N, si.push( vali ); )
+	TIMED( "copy_int", ti = si; )
+	TIMED( "clear_int", si.clear(); )
+	REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop()->as<integer>() ); /***/ )
+	REPEAT_TIMED( "print_int", N/2, print( out, vali, c_string{":"}, vali, c_string{"\n"} ); )
 
-	ptr<pair> max1 = make<pair>( make<boolean>(false), make<character>('\0') );
-	stack s1, t1;
+	ptr<pair> maxp = make<pair>( make<boolean>(false), make<character>('\0') );
+	pair valp{ make<boolean>(true), make<character>('a') };
+	stack sp, tp;
 	
-	REPEAT_TIMED( "push_bool_char", 
-		s1.push( make<pair>( make<boolean>(_i & 1), make<character>(_i & 0x7F) ) ); )
-	TIMED( "copy_bool_char", t1 = s1; )
-	TIMED( "clear_bool_char", s1.clear(); )
-	REPEAT_TIMED( "pop_bool_char",
-		ptr<pair> x = as_ptr<pair>( t1.pop() ); /***/
-		if ( *x > *max1 ) { max1 = std::move(x); } )
-	print( out, *max1, c_string{"\n"} );
-	REPEAT_N_TIMED( "print_pair", N/2, 
-		print( out, pair{ make<boolean>(_i & 1), make<character>(_i & 0x7F) }, c_string{":"}, 
-			pair{ make<boolean>(_i & 1), make<character>(_i & 0x7F) }, c_string{"\n"} ); )
+	REPEAT_TIMED( "push_pair", N, sp.push( valp ); )
+	TIMED( "copy_pair", tp = sp; )
+	TIMED( "clear_pair", sp.clear(); )
+	REPEAT_TIMED( "pop_pair", N, 
+		ptr<pair> xp = as_ptr<pair>( tp.pop() ); /***/
+		if ( *xp > *maxp ) { maxp = std::move(xp); } )
+	REPEAT_TIMED( "print_pair", N/2, print( out, valp, c_string{":"}, valp, c_string{"\n"} ); )
 }
Index: doc/generic_types/evaluation/cpp-vstack.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-vstack.cpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-vstack.cpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -2,6 +2,5 @@
 #include <utility>
 
-stack::node::node( const object& v ) : value( v.new_copy() ), next( nullptr ) {}
-stack::node::node( ptr<object>&& v, node* n ) : value( std::move(v) ), next( n ) {}
+stack::node::node( const object& v, node* n ) : value( v.new_copy() ), next( n ) {}
 
 void stack::copy(const stack& o) {
@@ -48,5 +47,5 @@
 bool stack::empty() const { return head == nullptr; }
 
-void stack::push(ptr<object>&& value) { head = new node{ std::move(value), head }; /***/ }
+void stack::push(const object& value) { head = new node{ value, head }; /***/ }
 
 ptr<object> stack::pop() {
Index: doc/generic_types/evaluation/cpp-vstack.hpp
===================================================================
--- doc/generic_types/evaluation/cpp-vstack.hpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/cpp-vstack.hpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -7,6 +7,5 @@
 		node* next;
 
-		node( const object& v );
-		node( ptr<object>&& v, node* n );
+		node( const object& v, node* n = nullptr );
 	};
 	node* head;
@@ -23,5 +22,5 @@
 	void clear();
 	bool empty() const;
-	void push(ptr<object>&& value);
+	void push(const object& value);
 	ptr<object> pop();
 };
Index: doc/generic_types/evaluation/object.hpp
===================================================================
--- doc/generic_types/evaluation/object.hpp	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/object.hpp	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -72,4 +72,6 @@
 	boolean() = default;
 	boolean(bool x) : x(x) {}
+	boolean(const boolean&) = default;
+	boolean(boolean&&) = default;
 	ptr<object> new_inst() const override { return make<boolean>(); }
 	ptr<object> new_copy() const override { return make<boolean>(*this); }
@@ -79,4 +81,5 @@
 	}
 	object& operator= (const object& that) override { return *this = that.as<boolean>(); } /***/
+	boolean& operator= (boolean&&) = default;
 	~boolean() override = default;
 
@@ -92,4 +95,6 @@
 	character() = default;
 	character(char x) : x(x) {}
+	character(const character&) = default;
+	character(character&&) = default;
 	ptr<object> new_inst() const override { return make<character>(); }
 	ptr<object> new_copy() const override { return make<character>(*this); }
@@ -99,4 +104,5 @@
 	}
 	object& operator= (const object& that) override { return *this = that.as<character>(); } /***/
+	character& operator= (character&&) = default;
 	~character() override = default;
 
@@ -115,4 +121,6 @@
 	integer() = default;
 	integer(int x) : x(x) {}
+	integer(const integer&) = default;
+	integer(integer&&) = default;
 	ptr<object> new_inst() const override { return make<integer>(); }
 	ptr<object> new_copy() const override { return make<integer>(*this); }
@@ -122,4 +130,5 @@
 	}
 	object& operator= (const object& that) override { return *this = that.as<integer>(); } /***/
+	integer& operator= (integer&&) = default;
 	~integer() override = default;
 
@@ -136,4 +145,6 @@
 	c_string() : s(empty) {}
 	c_string(const char* s) : s(s) {}
+	c_string(const c_string&) = default;
+	c_string(c_string&&) = default;
 	ptr<object> new_inst() const override { return make<c_string>(); }
 	ptr<object> new_copy() const override { return make<c_string>(s); }
@@ -143,4 +154,5 @@
 	}
 	object& operator= (const object& that) override { return *this = that.as<c_string>(); } /***/
+	c_string& operator= (c_string&&) = default;
 	~c_string() override = default;
 
@@ -154,4 +166,6 @@
 	pair() = default;
 	pair(ptr<object>&& x, ptr<object>&& y) : x(std::move(x)), y(std::move(y)) {}
+	pair(const pair& that) : x(that.x->new_copy()), y(that.y->new_copy()) {}
+	pair(pair&& that) : x(std::move(that.x)), y(std::move(that.y)) {}
 	ptr<object> new_inst() const override { return make<pair>(); }
 	ptr<object> new_copy() const override { return make<pair>(x->new_copy(), y->new_copy()); }
@@ -162,4 +176,9 @@
 	}
 	object& operator= (const object& that) override { return *this = that.as<pair>(); } /***/
+	pair& operator= (pair&& that) {
+		x = std::move(that.x);
+		y = std::move(that.y);
+		return *this;
+	}
 	~pair() override = default;
 
Index: doc/generic_types/evaluation/pair
===================================================================
--- doc/generic_types/evaluation/pair	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ 	(revision )
@@ -1,28 +1,0 @@
-#pragma once
-
-forall(otype R, otype S) struct pair {
-	R first;
-	S second;
-};
-
-forall(otype R, otype S 
-	| { int ?==?(R, R); int ?<?(R, R); int ?<?(S, S); })
-int ?<?(pair(R, S) p, pair(R, S) q);
-
-forall(otype R, otype S 
-	| { int ?==?(R, R); int ?<?(R, R); int ?<=?(S, S); })
-int ?<=?(pair(R, S) p, pair(R, S) q);
-
-forall(otype R, otype S | { int ?==?(R, R); int ?==?(S, S); })
-int ?==?(pair(R, S) p, pair(R, S) q);
-
-forall(otype R, otype S | { int ?!=?(R, R); int ?!=?(S, S); })
-int ?!=?(pair(R, S) p, pair(R, S) q);
-
-forall(otype R, otype S 
-	| { int ?==?(R, R); int ?>?(R, R); int ?>?(S, S); })
-int ?>?(pair(R, S) p, pair(R, S) q);
-
-forall(otype R, otype S 
-	| { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); })
-int ?>=?(pair(R, S) p, pair(R, S) q);
Index: doc/generic_types/evaluation/timing.dat
===================================================================
--- doc/generic_types/evaluation/timing.dat	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/evaluation/timing.dat	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -1,12 +1,11 @@
 "400 million repetitions"	"C"	"\\CFA{}"	"\\CC{}"	"\\CC{obj}"
-"push\nint"	3324	2263	1583	3141
-"copy\nint"	2999	2055	1560	3136
-"clear\nint"	1384	816	754	1498
-"pop\nint"	1413	1172	751	5344
-"print\nint"	7106	12458	3976	4044
-"push\npair"	4916	3139	1014	6407
-"copy\npair"	6218	2077	1002	7067
-"clear\npair"	2777	886	722	3519
-"pop\npair"	2857	4200	784	21145
-"print\npair"	13536	21726	9009	20516
-
+"push\nint"	2958	2480	1519	3284
+"copy\nint"	2961	2014	1534	3126
+"clear\nint"	1350	817	722	1459
+"pop\nint"	1386	1174	717	5404
+"print\nint"	5702	6615	3077	3191
+"push\npair"	4160	2648	940	6566
+"copy\npair"	6195	2099	977	7234
+"clear\npair"	2834	863	723	3315
+"pop\npair"	2956	5591	775	26256
+"print\npair"	7498	10804	8750	16638
Index: doc/generic_types/generic_types.tex
===================================================================
--- doc/generic_types/generic_types.tex	(revision 33e22da80a429fb642fe067c8cf5f189f62d63eb)
+++ doc/generic_types/generic_types.tex	(revision c87cd93912bc71baa2e5f84533ed9ab8bb2a5d23)
@@ -964,23 +964,27 @@
 \begin{figure}
 \begin{lstlisting}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt]
-int main( int argc, char * argv[] ) {
+int main( int argc, char *argv[] ) {
 	FILE * out = fopen( "cfa-out.txt", "w" );
-	int max = 0, vali = 42;
+	int maxi = 0, vali = 42;
 	stack(int) si, ti;
 
-	REPEAT_TIMED( "push_int", push( &si, vali ); )
+	REPEAT_TIMED( "push_int", N, push( &si, vali ); )
 	TIMED( "copy_int", ti = si; )
 	TIMED( "clear_int", clear( &si ); )
-	REPEAT_TIMED( "pop_int", max = max( max, pop( &ti ) ); )
-	REPEAT_TIMED( "print_int", print( out, vali, ":", vali, "\n" ); )
-
-	pair(_Bool, char) maxp  = { (_Bool)0, '\0' }, valp = { (_Bool)0, 'a' };
+	REPEAT_TIMED( "pop_int", N, 
+		int xi = pop( &ti ); 
+		if ( xi > maxi ) { maxi = xi; } )
+	REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); )
+
+	pair(_Bool, char) maxp = { (_Bool)0, '\0' }, valp = { (_Bool)1, 'a' };
 	stack(pair(_Bool, char)) sp, tp;
 
-	REPEAT_TIMED( "push_pair", push( &sp, valp ); )
+	REPEAT_TIMED( "push_pair", N, push( &sp, valp ); )
 	TIMED( "copy_pair", tp = sp; )
 	TIMED( "clear_pair", clear( &sp ); )
-	REPEAT_TIMED( "pop_pair", maxp = max( maxp, pop( &tp ) ); )
-	REPEAT_TIMED( "print_pair", print( out, valp, ":", valp, "\n" ); )
+	REPEAT_TIMED( "pop_pair", N, 
+		pair(_Bool, char) xp = pop( &tp ); 
+		if ( xp > maxp ) { maxp = xp; } )
+	REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); )
 	fclose(out);
 }
@@ -1008,8 +1012,8 @@
 \begin{tabular}{rrrrr}
 									& \CT{C}	& \CT{\CFA}	& \CT{\CC}	& \CT{\CCV}		\\ \hline
-maximum memory usage (MB)			& 10001		& 2501		& 2503		& 11253			\\
-source code size (lines)			& 301		& 224		& 188		& 437			\\
-redundant type annotations (lines)	& 46		& 3			& 2			& 15			\\
-binary size (KB)					& 18		& 234		& 18		& 42			\\
+maximum memory usage (MB)			& 10001		& 2502		& 2503		& 11253			\\
+source code size (lines)			& 247		& 223		& 165		& 339			\\
+redundant type annotations (lines)	& 39		& 2			& 2			& 15			\\
+binary size (KB)					& 14		& 229		& 18		& 38			\\
 \end{tabular}
 \end{table}
