diff --git a/core/stl.c b/core/stl.c
index cc45a35e..a3415cb0 100644
--- a/core/stl.c
+++ b/core/stl.c
@@ -367,8 +367,8 @@ int gst_stl_string(Gst *vm) {
     gst_c_return(vm, gst_wrap_string(gst_string_end(vm, str)));
 }
 
-/* Associative rawget */
-int gst_stl_rawget(Gst *vm) {
+/* Associative get */
+int gst_stl_get(Gst *vm) {
     GstValue ret;
     uint32_t count;
     const char *err;
@@ -382,8 +382,8 @@ int gst_stl_rawget(Gst *vm) {
         gst_c_return(vm, ret);
 }
 
-/* Associative rawset */
-int gst_stl_rawset(Gst *vm) {
+/* Associative set */
+int gst_stl_set(Gst *vm) {
     uint32_t count;
     const char *err;
     count = gst_count_args(vm);
@@ -652,17 +652,17 @@ static const GstModuleItem const std_module[] = {
     {"print", gst_stl_print},
     {"tostring", gst_stl_tostring},
     {"exit", gst_stl_exit},
-    {"rawget", gst_stl_rawget},
-    {"rawset", gst_stl_rawset},
+    {"get", gst_stl_get},
+    {"set!", gst_stl_set},
     {"next", gst_stl_next},
     {"error", gst_stl_error},
     {"serialize", gst_stl_serialize},
     {"global", gst_stl_global},
-    {"setglobal", gst_stl_setglobal},
-    {"push", gst_stl_push},
-    {"pop", gst_stl_pop},
+    {"setglobal!", gst_stl_setglobal},
+    {"push!", gst_stl_push},
+    {"pop!", gst_stl_pop},
     {"peek", gst_stl_peek},
-    {"ensure", gst_stl_ensure},
+    {"ensure!", gst_stl_ensure},
     {"open", gst_stl_open},
     {"slurp", gst_stl_slurp},
     {"read", gst_stl_read},
diff --git a/libs/pp.gst b/libs/pp.gst
index be47fd13..f379190d 100644
--- a/libs/pp.gst
+++ b/libs/pp.gst
@@ -4,56 +4,56 @@
 (: pp nil)
 
 # Pretty print an array or tuple
-(: print-seq (fn [start end a]
-    (: parts [])
-    (: len (length a))
-    (: i 0)
-    (while (< i len)
-        (push parts (pp (rawget a i)))
-        (push parts " ")
-        (: i (+ 1 i)))
-    (if (> len 0) (pop parts))
-    (push parts end)
-    (apply string start parts)))
+(: print-seq (fn [start end a seen]
+    (: seen (if seen seen {}))
+    (if (get seen s) (get seen s)
+        (do
+            (: parts [])
+            (: len (length a))
+            (: i 0)
+            (while (< i len)
+                (push! parts (pp (get a i) seen))
+                (push! parts " ")
+                (: i (+ 1 i)))
+            (if (> len 0) (pop! parts))
+            (push! parts end)
+            (: ret (apply string start parts))
+            (set! seen s ret)
+            ret))))
 
 # Pretty print an object or struct
-(: print-struct (fn [start end s]
-    (: parts [])
-    (: key (next s))
-    (while (not (= key nil))
-        (push parts (pp key))
-        (push parts " ")
-        (push parts (pp (rawget s key)))
-        (push parts " ")
-        (: key (next s key)))
-    (if (> (length parts) 0) (pop parts))
-    (push parts end)
-    (apply string start parts)))
-
-# Pretty 
+(: print-struct (fn [start end s seen]
+    (: seen (if seen seen {}))
+    (if (get seen s) (get seen s)
+        (do
+            (: parts [])
+            (: key (next s))
+            (while (not (= key nil))
+                    (push! parts (pp key seen))
+                    (push! parts " ")
+                    (push! parts (pp (get s key) seen))
+                    (push! parts " ")
+                    (: key (next s key)))
+            (if (> (length parts) 0) (pop! parts))
+            (push! parts end)
+            (: ret (apply string start parts))
+            (set! seen s ret)
+            ret))))
 
+# Type handlers
 (: handlers {
-    "real" tostring
-    "integer" tostring
-    "nil" tostring
-    "boolean" tostring
-    "userdata" tostring
-    "cfunction" tostring
-    "function" tostring
-    "string" tostring
-    "buffer" tostring
-    "array" (fn [a] (print-seq "[" "]" a))
-    "tuple" (fn [a] (print-seq "(" ")" a))
-    "object" (fn [s] (print-struct "{" "}" s))
-    "struct" (fn [s] (print-struct "#{" "}" s))
-    "thread" tostring 
+    "array" (fn [a seen] (print-seq "[" "]" a seen))
+    "tuple" (fn [a seen] (print-seq "(" ")" a seen))
+    "table" (fn [s seen] (print-struct "{" "}" s seen))
+    "struct" (fn [s seen] (print-struct "#{" "}" s seen))
  })
 
 # Define pretty print
-(: pp (fn [x]
-    (: h (rawget handlers (type x)))
-    (h x)))
+(: pp (fn [x seen]
+    (: h (get handlers (type x)))
+    ((if h h tostring) x seen)))
 
 (print (pp [1 {4 5 6 7} 2 3]))
 
-(print "DONE!")
+# Module export pattern - last expression in file is value of module
+pp