Index: src/Common/GC.h
===================================================================
--- src/Common/GC.h	(revision 184557ed94d1cdbdc6fd685e497e5375f8968a96)
+++ src/Common/GC.h	(revision 5c140301192225f6a3f669eb918000f25962a75e)
@@ -69,4 +69,27 @@
 	bool mark;                     ///< The current collection's mark bit
 	unsigned g;                    ///< The current number generation in use
+
+	/// Trace a traceable object (enabled by SFINAE)
+	template<typename T>
+	static inline auto do_trace(const GC& gc, T& obj, int) -> decltype(gc << obj, void()) {
+		gc << obj;
+	}
+
+	/// Do not trace an untraceable object
+	template<typename T>
+	static inline auto do_trace(const GC&, T&, long) -> void {}
+
+	/// Base case for maybe_trace
+	void maybe_trace() const {}
+
+public:
+	/// Trace any objects that are traceable
+	template<typename T, typename... Args>
+	void maybe_trace(T& obj, Args&... args) const {
+		// uses SFINAE trick to select proper overload; prefers actually tracing version 
+		// (because of int->long conversion), but will fall back to non-tracing
+		do_trace(*this, obj, 0);
+		maybe_trace(args...);
+	}
 };
 
Index: src/Common/PersistentDisjointSet.h
===================================================================
--- src/Common/PersistentDisjointSet.h	(revision 184557ed94d1cdbdc6fd685e497e5375f8968a96)
+++ src/Common/PersistentDisjointSet.h	(revision 5c140301192225f6a3f669eb918000f25962a75e)
@@ -129,4 +129,10 @@
 	}
 
+	/// reset as base
+	void reset_as_base() {
+		assertf( mode == BASE, "can only reset_as_base() on BASE" );
+		as<Base>().~Base();
+	}
+
 	/// Non-initializing constructor; should call init() before use
 	PersistentDisjointSet( Mode m ) : data(), mode(m) {}
@@ -165,5 +171,5 @@
 			case BASE: {
 				for (const auto& entry : as<Base>()) {
-					gc << entry.first;
+					gc.maybe_trace( entry.first );
 				}
 				return;
@@ -171,10 +177,12 @@
 			case ADD: case REM: {
 				const Add& self = as<Add>();
-				gc << self.base << self.root;
+				gc << self.base; 
+				gc.maybe_trace( self.root );
 				return;
 			}
 			case ADDTO: case REMFROM: {
 				const AddTo& self = as<AddTo>();
-				gc << self.base << self.root << self.child;
+				gc << self.base;
+				gc.maybe_trace( self.root, self.child );
 				return;
 			}
@@ -210,5 +218,5 @@
 		// take map out of base
 		Base base_map = base->take_as<Base>();
-		base->reset();
+		base->reset_as_base();
 
 		// switch base to inverse of self and mutate base map
@@ -331,5 +339,5 @@
 		// transfer map to new node
 		Self* ret = new Self{ BASE, take_as<Base>() };
-		reset();
+		reset_as_base();
 
 		// set self to REM node
@@ -352,5 +360,5 @@
 		// transfer map to new node
 		Self* ret = new Self{ BASE, take_as<Base>() };
-		reset();
+		reset_as_base();
 
 		// find set nodes
@@ -449,5 +457,5 @@
 	/// `f` should take members by const reference or copy
 	template<typename F>
-	void apply_to_class(Elm i, F&& f) const {
+	void for_class(Elm i, F&& f) const {
 		const Base& self = rerooted();
 
Index: src/Common/PersistentMap.h
===================================================================
--- src/Common/PersistentMap.h	(revision 184557ed94d1cdbdc6fd685e497e5375f8968a96)
+++ src/Common/PersistentMap.h	(revision 5c140301192225f6a3f669eb918000f25962a75e)
@@ -139,5 +139,5 @@
 			case BASE: {
 				for (const auto& entry : as<Base>()) {
-					gc << entry.first << entry.second;
+					gc.maybe_trace( entry.first, entry.second );
 				}
 				return;
@@ -145,10 +145,12 @@
 			case REM: {
 				const Rem& self = as<Rem>();
-				gc << self.base << self.key;
+				gc << self.base;
+				gc.maybe_trace( self.key );
 				return;
 			}
 			case INS: case UPD: {
 				const Ins& self = as<Ins>();
-				gc << self.base << self.key << self.val;
+				gc << self.base;
+				gc.maybe_trace( self.key, self.val );
 				return;
 			}
@@ -424,4 +426,11 @@
 	}
 
+	/// Applies the function `f` to all elements of the map.
+	/// `f` should take two parameters, `const Key&` and `const Val&`.
+	template<typename F>
+	void for_each(F&& f) const {
+		for ( const auto& entry : rerooted() ) { f( entry.first, entry.second ); }
+	}
+
 	/// Applies the function `f` to all elements of the map, returning a pointer to the updated map.
 	/// `f` should take two parameters, `const Key&` and `Val&`, returning option<Val> filled with 
@@ -429,5 +438,5 @@
 	/// NOTE: when porting to C++17, this should work fine with std::optional
 	template<typename F>
-	Self* apply_to_all(F&& f) {
+	Self* mutate_each(F&& f) {
 		// reset to root and exit early if no change
 		if ( rerooted().empty() ) return this;
@@ -454,11 +463,4 @@
 		return next_edit;
 	}
-
-	/// Applies the function `f` to all elements of the map.
-	/// `f` should take two parameters, `const Key&` and `const Val&`.
-	template<typename F>
-	void apply_to_all(F&& f) const {
-		for ( const auto& entry : rerooted() ) { f( entry.first, entry.second ); }
-	}
 };
 
Index: src/Common/option.h
===================================================================
--- src/Common/option.h	(revision 184557ed94d1cdbdc6fd685e497e5375f8968a96)
+++ src/Common/option.h	(revision 5c140301192225f6a3f669eb918000f25962a75e)
@@ -16,9 +16,8 @@
 #pragma once
 
+#include <cassert>
 #include <functional>
 #include <type_traits>
 #include <utility>
-
-#include "debug.h"
 
 using std::move;
@@ -121,8 +120,8 @@
 
     /// Get contained value (checked)
-    T& value() & { assume(filled, "checked get failed"); return get(); }
-    const T& value() const& { assume(filled, "checked get failed"); return get(); }
-    T&& value() && { assume(filled, "checked get failed"); return move(get()); }
-    const T&& value() const&& { assume(filled, "checked get failed"); return move(get()); }
+    T& value() & { assertf(filled, "checked get failed"); return get(); }
+    const T& value() const& { assertf(filled, "checked get failed"); return get(); }
+    T&& value() && { assertf(filled, "checked get failed"); return move(get()); }
+    const T&& value() const&& { assertf(filled, "checked get failed"); return move(get()); }
 
     /// Get contained or default value
