Index: tests/exceptions/.expect/message.txt
===================================================================
--- tests/exceptions/.expect/message.txt	(revision 190a833c2baaf0fb88c72cb00720c5ab476197bc)
+++ tests/exceptions/.expect/message.txt	(revision 190a833c2baaf0fb88c72cb00720c5ab476197bc)
@@ -0,0 +1,2 @@
+Out of Range Index 10 (expected less than 8)
+5
Index: tests/exceptions/message.cfa
===================================================================
--- tests/exceptions/message.cfa	(revision 190a833c2baaf0fb88c72cb00720c5ab476197bc)
+++ tests/exceptions/message.cfa	(revision 190a833c2baaf0fb88c72cb00720c5ab476197bc)
@@ -0,0 +1,71 @@
+// Use of the exception system where we provide our own functions.
+
+#include <stdio.h>
+#include <string.h>
+// Using collections/string.hfa leads to a resolution error on snprintf.
+
+exception BadIndexException {
+	int value;
+	int size;
+	char * message;
+};
+
+const char * virtual_msg(BadIndexException * this) {
+	return this->virtual_table->msg(this);
+}
+
+// Array length calculated to ususually be big enough.
+const size_t msg_size = 52;
+
+char * format_bad_index(int value, int size) {
+	char * out = (char *)(void *)malloc(msg_size + 1);
+	snprintf(out, msg_size,
+		"Out of Range Index %d (expected less than %d)", value, size);
+	return out;
+}
+
+const char * msg(BadIndexException * this) {
+	if (this->message) {
+		free(this->message);
+	}
+	this->message = format_bad_index(this->value, this->size);
+	return this->message;
+}
+
+void copy(BadIndexException * dst, BadIndexException * src) {
+	// This is an easy detail to miss, you have to copy the table over.
+	dst->virtual_table = src->virtual_table;
+
+	dst->value = src->value;
+	dst->size = src->size;
+	dst->message = (src->message) ? strndup(src->message, msg_size) : 0p;
+}
+
+void ^?{}(BadIndexException & this) {
+	free(this.message);
+}
+
+vtable(BadIndexException) arrayIndex = {
+	.msg = msg,
+	.copy = copy,
+	.^?{} = ^?{},
+};
+
+// This is not supposed to be a real range check, but that's the idea:
+void failRangeCheck(int index, int size) {
+	throw (BadIndexException){ &arrayIndex, index, size };
+}
+
+int atDefault(int fallback) {
+	try {
+		failRangeCheck(10, 8);
+	} catch (BadIndexException * error) {
+		printf("%s\n", virtual_msg(error));
+	}
+	return fallback;
+}
+
+int main() {
+	int value = atDefault(5);
+	printf("%d\n", value);
+}
