bind: remove error wrappers to preserve error instance identity

CL 24800 changed the error representation from strings to objects.
However, since native errors types are not immediately compatible
across languages, wrapper types were introduced to bridge the gap.

This CL remove those wrappers and instead special case the error
proxy types to conform to their language error protocol.

Specifically:

 - The ObjC proxy for Go errors now extends NSError and calls
   initWithDomain to store the error message.
 - The Go proxy for ObjC NSError return the localizedDescription
    property for calls to Error.
 - The Java proxy for Go errors ow extends Exception and
   overrides getMessage() to return the error message.
 - The Go proxy for Java Exceptions returns getMessage whenever
   Error is called.

The end result is that error values behave more like normal objects
across the language boundary. In particular, instance identity is
now preserved: an error passed across the boundary and back will
result in the same instance.

There are two semantic changes that followed this change:

 - The domain for wrapped Go errors is now always "go".
   The domain wasn't useful before this CL: the domains were set to
   the package name of function or method where the error happened
   to cross the language boundary.
 - If a Go method that returns an error is implemented in ObjC, the
   implementation must now both return NO _and_ set the error result
   for the calling Go code to receive a non-nil error.
   Before this CL, because errors were always wrapped, a nil ObjC
   could be represented with a non-nil wrapper.

Change-Id: Idb415b6b13ecf79ccceb60f675059942bfc48fec
Reviewed-on: https://go-review.googlesource.com/29298
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/genclasses.go b/bind/genclasses.go
index 30f375d..465a0c8 100644
--- a/bind/genclasses.go
+++ b/bind/genclasses.go
@@ -302,7 +302,7 @@
 		g.Printf(", _a%d", i)
 	}
 	g.Printf(");\n")
-	g.Printf("jobject _exc = go_seq_wrap_exception(env);\n")
+	g.Printf("jobject _exc = go_seq_get_exception(env);\n")
 	g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
 	if f.Ret != nil {
 		g.genJavaToC("res", f.Ret)
@@ -370,7 +370,7 @@
 			g.Printf(", _a%d", i)
 		}
 		g.Printf(");\n")
-		g.Printf("jobject _exc = go_seq_wrap_exception(env);\n")
+		g.Printf("jobject _exc = go_seq_get_exception(env);\n")
 		g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
 		if f.Ret != nil {
 			g.genJavaToC("res", f.Ret)
diff --git a/bind/genjava.go b/bind/genjava.go
index 589af2f..ee5d65a 100644
--- a/bind/genjava.go
+++ b/bind/genjava.go
@@ -120,6 +120,15 @@
 	return nil
 }
 
+func (g *JavaGen) genProxyImpl(name string) {
+	g.Printf("private final Seq.Ref ref;\n\n")
+	g.Printf("@Override public final int incRefnum() {\n")
+	g.Printf("      int refnum = ref.refnum;\n")
+	g.Printf("      Seq.incGoRef(refnum);\n")
+	g.Printf("      return refnum;\n")
+	g.Printf("}\n\n")
+}
+
 func (g *JavaGen) genStruct(s structInfo) {
 	pkgPath := ""
 	if g.Pkg != nil {
@@ -140,6 +149,8 @@
 				impls = append(impls, cls.Name)
 			}
 		}
+	} else {
+		impls = append(impls, "Seq.Proxy")
 	}
 
 	pT := types.NewPointer(s.obj.Type())
@@ -158,8 +169,6 @@
 		if jinf.extends != nil {
 			g.Printf(" extends %s", jinf.extends.Name)
 		}
-	} else {
-		g.Printf(" extends Seq.Proxy")
 	}
 	if len(impls) > 0 {
 		g.Printf(" implements %s", strings.Join(impls, ", "))
@@ -168,8 +177,8 @@
 	g.Indent()
 
 	g.Printf("static { %s.touch(); }\n\n", g.className())
+	g.genProxyImpl(n)
 	if jinf != nil {
-		g.Printf("private final Seq.Ref ref;\n\n")
 		for _, f := range jinf.cons {
 			if !g.isSigSupported(f.Type()) {
 				g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name())
@@ -184,13 +193,8 @@
 			g.Printf("public %s() { this.ref = __New(); }\n\n", n)
 			g.Printf("private static native Seq.Ref __New();\n\n")
 		}
-		g.Printf("@Override public final int incRefnum() {\n")
-		g.Printf("	int refnum = ref.refnum;\n")
-		g.Printf("	Seq.incGoRef(refnum);\n")
-		g.Printf("	return refnum;\n")
-		g.Printf("}\n\n")
 	} else {
-		g.Printf("%s(Seq.Ref ref) { super(ref); }\n\n", n)
+		g.Printf("%s(Seq.Ref ref) { this.ref = ref; }\n\n", n)
 	}
 
 	for _, f := range fields {
@@ -1090,7 +1094,7 @@
 			rets = append(rets, retName)
 		}
 		if res.Len() == 2 || isErrorType(t) {
-			g.Printf("jobject exc = go_seq_wrap_exception(env);\n")
+			g.Printf("jobject exc = go_seq_get_exception(env);\n")
 			errType := types.Universe.Lookup("error").Type()
 			g.genJavaToC("exc", errType, modeRetained)
 			retName = "_exc"
@@ -1288,6 +1292,13 @@
 		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+className(pkg)+"$proxy"+iface.obj.Name())
 		g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name())
 		g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(Lgo/Seq$Ref;)V\");\n", g.pkgPrefix, iface.obj.Name())
+		if isErrorType(iface.obj.Type()) {
+			// As a special case, Java Exceptions are passed to Go pretending to implement the Go error interface.
+			// To complete the illusion, use the Throwable.getMessage method for proxied calls to the error.Error method.
+			g.Printf("clazz = (*env)->FindClass(env, \"java/lang/Throwable\");\n")
+			g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n")
+			continue
+		}
 		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+iface.obj.Name())
 		for _, m := range iface.summary.callable {
 			if !g.isSigSupported(m.Type()) {
@@ -1390,12 +1401,22 @@
 	g.Printf("private static native void _init();\n\n")
 
 	for _, iface := range g.interfaces {
-		g.Printf(javaProxyPreamble, iface.obj.Name())
+		n := iface.obj.Name()
+		g.Printf("private static final class proxy%s", n)
+		if isErrorType(iface.obj.Type()) {
+			g.Printf(" extends Exception")
+		}
+		g.Printf(" implements Seq.Proxy, %s {\n", n)
 		g.Indent()
+		g.genProxyImpl("proxy" + n)
+		g.Printf("proxy%s(Seq.Ref ref) { this.ref = ref; }\n\n", n)
 
+		if isErrorType(iface.obj.Type()) {
+			g.Printf("@Override public String getMessage() { return error(); }\n\n")
+		}
 		for _, m := range iface.summary.callable {
 			if !g.isSigSupported(m.Type()) {
-				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
+				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name())
 				continue
 			}
 			g.Printf("public native ")
@@ -1461,10 +1482,6 @@
 }
 
 const (
-	javaProxyPreamble = `private static final class proxy%[1]s extends Seq.Proxy implements %[1]s {
-	proxy%[1]s(Seq.Ref ref) { super(ref); }
-
-`
 	javaPreamble = `// Java class %[1]s.%[2]s is a proxy for talking to a Go program.
 //   gobind %[3]s %[4]s
 //
diff --git a/bind/genobjc.go b/bind/genobjc.go
index 49467f0..b1ab0ff 100644
--- a/bind/genobjc.go
+++ b/bind/genobjc.go
@@ -193,12 +193,8 @@
 
 func (g *objcGen) genM() error {
 	var pkgPath string
-	var errDomain string
 	if g.Pkg != nil {
 		pkgPath = g.Pkg.Path()
-		errDomain = "go." + pkgPath
-	} else {
-		errDomain = "go"
 	}
 	g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath)
 	g.Printf("#include <Foundation/Foundation.h>\n")
@@ -206,8 +202,6 @@
 	g.Printf("#include \"_cgo_export.h\"\n")
 	g.Printf("#include %q\n", g.namePrefix+".h")
 	g.Printf("\n")
-	g.Printf("static NSString* errDomain = @%q;\n", errDomain)
-	g.Printf("\n")
 
 	// struct
 	for _, s := range g.structs {
@@ -676,7 +670,7 @@
 			if isErrorType(p.typ) {
 				g.Printf("if (_%s != nil && %s != nil) {\n", p.name, p.name)
 				g.Indent()
-				g.Printf("*%s = go_seq_to_nserror(_%s, errDomain);\n", p.name, p.name)
+				g.Printf("*%s = _%s;\n", p.name, p.name)
 				g.Outdent()
 				g.Printf("}\n")
 			} else {
@@ -696,14 +690,19 @@
 }
 
 func (g *objcGen) genInterfaceInterface(obj *types.TypeName, summary ifaceSummary, isProtocol bool) {
-	g.Printf("@interface %[1]s%[2]s : NSObject", g.namePrefix, obj.Name())
+	g.Printf("@interface %[1]s%[2]s : ", g.namePrefix, obj.Name())
+	if isErrorType(obj.Type()) {
+		g.Printf("NSError")
+	} else {
+		g.Printf("NSObject")
+	}
 	if isProtocol {
 		g.Printf(" <%[1]s%[2]s>", g.namePrefix, obj.Name())
 	}
 	g.Printf(" {\n}\n")
 	g.Printf("@property(strong, readonly) id _ref;\n")
 	g.Printf("\n")
-	g.Printf("- (id)initWithRef:(id)ref;\n")
+	g.Printf("- (instancetype)initWithRef:(id)ref;\n")
 	for _, m := range summary.callable {
 		if !g.isSigSupported(m.Type()) {
 			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
@@ -740,10 +739,17 @@
 	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
 	g.Printf("}\n")
 	g.Printf("\n")
-	g.Printf("- (id)initWithRef:(id)ref {\n")
+	g.Printf("- (instancetype)initWithRef:(id)ref {\n")
 	g.Indent()
-	g.Printf("self = [super init];\n")
-	g.Printf("if (self) { __ref = ref; }\n")
+	if isErrorType(obj.Type()) {
+		g.Printf("if (self) {\n")
+		g.Printf("	__ref = ref;\n")
+		g.Printf("	self = [super initWithDomain:@\"go\" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}];\n")
+		g.Printf("}\n")
+	} else {
+		g.Printf("self = [super init];\n")
+		g.Printf("if (self) { __ref = ref; }\n")
+	}
 	g.Printf("return self;\n")
 	g.Outdent()
 	g.Printf("}\n")
@@ -790,10 +796,16 @@
 		}
 	}
 
-	if s.ret == "void" {
-		g.Printf("[o %s];\n", s.callMethod(g))
+	if isErrorType(obj.Type()) && m.Name() == "Error" {
+		// As a special case, ObjC NSErrors are passed to Go pretending to implement the Go error interface.
+		// They don't actually have an Error method, so calls to to it needs to be rerouted.
+		g.Printf("NSString *returnVal = [o localizedDescription];\n")
 	} else {
-		g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g))
+		if s.ret == "void" {
+			g.Printf("[o %s];\n", s.callMethod(g))
+		} else {
+			g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g))
+		}
 	}
 
 	if len(s.retParams) > 0 {
@@ -812,7 +824,7 @@
 						g.Printf("if (%s != nil) {\n", p.name)
 					}
 					g.Indent()
-					g.Printf("_%[1]s = [[goSeqErrorWrapper alloc] initWithError:%[1]s];\n", p.name)
+					g.Printf("_%[1]s = %[1]s;\n", p.name)
 					g.Outdent()
 					g.Printf("}\n")
 					g.genWrite("_"+p.name, p.typ, modeRetained)
diff --git a/bind/java/Seq.java b/bind/java/Seq.java
index 2d636a9..b421a93 100644
--- a/bind/java/Seq.java
+++ b/bind/java/Seq.java
@@ -9,7 +9,6 @@
 import java.util.logging.Logger;
 
 import go.Universe;
-import go.error;
 
 // Seq is a sequence of machine-dependent encoded values.
 // Used by automatically generated language bindings to talk to Go.
@@ -48,18 +47,6 @@
 	private Seq() {
 	}
 
-	private static void throwException(error err) throws Exception {
-		throw new Exception(err.error());
-	}
-
-	private static error wrapThrowable(final Throwable t) {
-		return new error() {
-			@Override public String error() {
-				return t.getMessage();
-			}
-		};
-	}
-
 	// ctx is an android.context.Context.
 	static native void setContext(java.lang.Object ctx);
 
@@ -105,23 +92,10 @@
 		// invalidating it before being translated on the Go side.
 		int incRefnum();
 	}
-
 	// A Proxy is a Java object that proxies a Go object. Proxies, unlike
 	// GoObjects, are unwrapped to their Go counterpart when deserialized
 	// in Go.
-	public static abstract class Proxy implements GoObject {
-		private final Ref ref;
-
-		protected Proxy(Ref ref) {
-			this.ref = ref;
-		}
-
-		@Override public final int incRefnum() {
-			int refnum = ref.refnum;
-			Seq.incGoRef(refnum);
-			return refnum;
-		}
-	}
+	public interface Proxy extends GoObject {}
 
 	// A Ref is an object tagged with an integer for passing back and
 	// forth across the language boundary.
diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java
index 6348e01..5e6af55 100644
--- a/bind/java/SeqTest.java
+++ b/bind/java/SeqTest.java
@@ -416,11 +416,19 @@
   }
 
   public void testErrorField() {
-    final String want = "an error message";
     Node n = Testpkg.newNode("ErrTest");
-    n.setErr(new Exception(want));
+    Exception want = new Exception("an error message");
+    n.setErr(want);
     Exception got = n.getErr();
-    assertEquals("want back the error message we set", want, got.getMessage());
+    assertTrue("want back the error we set", want == got);
+    String msg = Testpkg.errorMessage(want);
+    assertEquals("the error message must match", want.getMessage(), msg);
+  }
+
+  public void testErrorDup() {
+    Exception err = Testpkg.getGlobalErr();
+    assertTrue("the Go error instance must preserve its identity", Testpkg.isGlobalErr(err));
+    assertEquals("the Go error message must be preserved", "global err", err.getMessage());
   }
 
   //test if we have JNI local reference table overflow error
diff --git a/bind/java/seq.h b/bind/java/seq.h
index 6c0ae58..363056d 100644
--- a/bind/java/seq.h
+++ b/bind/java/seq.h
@@ -39,9 +39,8 @@
 extern jobject go_seq_from_refnum(JNIEnv *env, int32_t refnum, jclass proxy_class, jmethodID proxy_cons);
 
 extern void go_seq_maybe_throw_exception(JNIEnv *env, jobject msg);
-// go_seq_wrap_exception wraps a pending exception in a Java object implementing the
-// golang/x/mobile/bind/errors.Error interface. If there is no pending exception, it returns NULL.
-extern jobject go_seq_wrap_exception(JNIEnv *env);
+// go_seq_get_exception returns any pending exception and clears the exception status.
+extern jobject go_seq_get_exception(JNIEnv *env);
 
 extern jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy);
 extern nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray s, int copy);
diff --git a/bind/java/seq_android.c.support b/bind/java/seq_android.c.support
index 19a57d3..495b9e2 100644
--- a/bind/java/seq_android.c.support
+++ b/bind/java/seq_android.c.support
@@ -25,13 +25,11 @@
 static pthread_key_t jnienvs;
 
 static jclass seq_class;
-static jmethodID seq_throw_exc;
 static jmethodID seq_getRef;
 static jmethodID seq_decRef;
 static jmethodID seq_incRef;
 static jmethodID seq_incGoObjectRef;
 static jmethodID seq_incRefnum;
-static jmethodID seq_wrapThrowable;
 
 static jfieldID ref_objField;
 
@@ -60,23 +58,19 @@
 	return env;
 }
 
-void go_seq_maybe_throw_exception(JNIEnv *env, jobject msg) {
-	if (msg != NULL) {
-		if ((*env)->IsInstanceOf(env, msg, throwable_class)) {
-			(*env)->Throw(env, msg);
-		} else {
-			(*env)->CallStaticVoidMethod(env, seq_class, seq_throw_exc, msg);
-		}
+void go_seq_maybe_throw_exception(JNIEnv *env, jobject exc) {
+	if (exc != NULL) {
+		(*env)->Throw(env, exc);
 	}
 }
 
-jobject go_seq_wrap_exception(JNIEnv *env) {
+jobject go_seq_get_exception(JNIEnv *env) {
 	jthrowable exc = (*env)->ExceptionOccurred(env);
 	if (!exc) {
 		return NULL;
 	}
 	(*env)->ExceptionClear(env);
-	return (*env)->CallStaticObjectMethod(env, seq_class, seq_wrapThrowable, exc);
+	return exc;
 }
 
 jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy) {
@@ -310,11 +304,6 @@
 	}
 
 	seq_class = (*env)->NewGlobalRef(env, clazz);
-	seq_throw_exc = (*env)->GetStaticMethodID(env, seq_class, "throwException", "(Lgo/error;)V");
-	if (seq_throw_exc == NULL) {
-		LOG_FATAL("failed to find method Seq.throwException");
-	}
-
 	seq_getRef = (*env)->GetStaticMethodID(env, seq_class, "getRef", "(I)Lgo/Seq$Ref;");
 	if (seq_getRef == NULL) {
 		LOG_FATAL("failed to find method Seq.getRef");
@@ -335,15 +324,6 @@
 	if (seq_incGoObjectRef == NULL) {
 		LOG_FATAL("failed to find method Seq.incGoObjectRef");
 	}
-	seq_wrapThrowable = (*env)->GetStaticMethodID(env, seq_class, "wrapThrowable", "(Ljava/lang/Throwable;)Lgo/error;");
-	if (seq_wrapThrowable == NULL) {
-		LOG_FATAL("failed to find method Seq.wrapThrowable");
-	}
-	throwable_class = (*env)->FindClass(env, "java/lang/Throwable");
-	if (throwable_class == NULL) {
-		LOG_FATAL("failed to find Throwable class");
-	}
-	throwable_class = (*env)->NewGlobalRef(env, throwable_class);
 	jclass ref_class = (*env)->FindClass(env, "go/Seq$Ref");
 	if (ref_class == NULL) {
 		LOG_FATAL("failed to find the Seq.Ref class");
diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m
index 7709131..8fd15cf 100644
--- a/bind/objc/SeqTest.m
+++ b/bind/objc/SeqTest.m
@@ -35,6 +35,7 @@
        }
        return true;
    }
+   *error = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: @"NumberError"}];
    return false;
 }
 
@@ -295,12 +296,20 @@
 }
 
 - (void)testErrorField {
-	NSString *want = @"an error message";
+	NSString *wantMsg = @"an error message";
+	NSError *want = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: wantMsg}];
 	GoTestpkgNode *n = GoTestpkgNewNode(@"ErrTest");
-	n.err = [NSError errorWithDomain:@"SeqTest" code:1 userInfo:@{NSLocalizedDescriptionKey: want}];
+	n.err = want;
 	NSError *got = n.err;
-	NSString *gotMsg = [got.userInfo valueForKey:NSLocalizedDescriptionKey];
-	XCTAssertEqualObjects(gotMsg, want, @"err = %@, want %@", gotMsg, want);
+	XCTAssertEqual(got, want, @"got different objects efter roundtrip");
+	NSString *gotMsg = GoTestpkgErrorMessage(want);
+	XCTAssertEqualObjects(gotMsg, wantMsg, @"err = %@, want %@", gotMsg, wantMsg);
+}
+
+- (void)testErrorDup {
+	NSError *err = GoTestpkg.globalErr;
+	XCTAssertTrue(GoTestpkgIsGlobalErr(err), @"A Go error must preserve its identity across the boundary");
+	XCTAssertEqualObjects([err localizedDescription], @"global err", "A Go error message must be preserved");
 }
 
 - (void)testVar {
@@ -343,6 +352,8 @@
 	NSString *ret;
 	NSError *error;
 	XCTAssertFalse(GoTestpkgCallIStringError(num, @"alphabet", &ret, &error), @"GoTestpkgCallIStringError(Number, 'alphabet') succeeded; want error");
+	NSString *desc = [error localizedDescription];
+	XCTAssertEqualObjects(desc, @"NumberError", @"GoTestpkgCallIStringError(Number, 'alphabet') returned unexpected error message %@", desc);
 	NSError *error2;
 	XCTAssertTrue(GoTestpkgCallIStringError(num, @"number", &ret, &error2), @"GoTestpkgCallIStringError(Number, 'number') failed(%@); want success", error2);
 	XCTAssertEqualObjects(ret, @"OK", @"GoTestpkgCallIStringError(Number, 'number') returned unexpected results %@", ret);
diff --git a/bind/objc/seq.h b/bind/objc/seq.h
index 8941760..f1f2e95 100644
--- a/bind/objc/seq.h
+++ b/bind/objc/seq.h
@@ -24,14 +24,6 @@
                               userInfo:NULL];                                  \
   }
 
-// goErrorWrapper is a adapter between an NSError * and the bind Error interface
-@interface goSeqErrorWrapper : NSObject<GoUniverseerror> {
-}
-@property NSError *err;
-
-- (id)initWithError:(NSError *)err;
-@end
-
 // GoSeqRef is an object tagged with an integer for passing back and
 // forth across the language boundary. A GoSeqRef may represent either
 // an instance of a Go object, or an Objective-C object passed to Go.
@@ -92,6 +84,5 @@
 
 extern NSData *go_seq_to_objc_bytearray(nbyteslice, int copy);
 extern NSString *go_seq_to_objc_string(nstring str);
-extern NSError *go_seq_to_nserror(id<GoUniverseerror> err, NSString *errDomain);
 
 #endif // __GO_SEQ_HDR__
diff --git a/bind/objc/seq_darwin.m.support b/bind/objc/seq_darwin.m.support
index 933a35f..917a4ef 100644
--- a/bind/objc/seq_darwin.m.support
+++ b/bind/objc/seq_darwin.m.support
@@ -49,22 +49,6 @@
 // Note that this file is copied into and compiled with the generated
 // bindings.
 
-@implementation goSeqErrorWrapper {
-}
-@synthesize err;
-
-- (id)initWithError:(NSError *)e {
-  if (!(self = [super init]))
-    return nil;
-  self.err = e;
-  return self;
-}
-
-- (NSString *)error {
-  return [self.err localizedDescription];
-}
-@end
-
 // A simple thread-safe mutable dictionary.
 @interface goSeqDictionary : NSObject {
 }
@@ -250,13 +234,6 @@
   return res;
 }
 
-NSError *go_seq_to_nserror(id<GoUniverseerror> err, NSString *errDomain) {
-	NSString *errStr = [err error];
-	NSMutableDictionary* details = [NSMutableDictionary dictionary];
-	[details setValue:errStr forKey:NSLocalizedDescriptionKey];
-	return [NSError errorWithDomain:errDomain code:1 userInfo:details];
-}
-
 @implementation GoSeqRef {
 }
 
diff --git a/bind/testdata/basictypes.objc.m.golden b/bind/testdata/basictypes.objc.m.golden
index 2f8bff7..3dbe443 100644
--- a/bind/testdata/basictypes.objc.m.golden
+++ b/bind/testdata/basictypes.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoBasictypes.h"
 
-static NSString* errDomain = @"go.basictypes";
-
 const BOOL GoBasictypesABool = YES;
 const double GoBasictypesAFloat = 0.2015;
 NSString* const GoBasictypesALongString = @"LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString";
@@ -47,7 +45,7 @@
 		}
 	}
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
@@ -65,7 +63,7 @@
 	}
 	*ret0_ = _ret0_;
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
diff --git a/bind/testdata/classes.java.c.golden b/bind/testdata/classes.java.c.golden
index 41942e1..c8c6a73 100644
--- a/bind/testdata/classes.java.c.golden
+++ b/bind/testdata/classes.java.c.golden
@@ -39,7 +39,7 @@
 	// Must be a Java object
 	jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
 	(*env)->CallVoidMethod(env, _this, m_java_lang_Runnable_run);
-	jobject _exc = go_seq_wrap_exception(env);
+	jobject _exc = go_seq_get_exception(env);
 	int32_t _exc_ref = go_seq_to_refnum(env, _exc);
 	go_seq_pop_local_frame(env);
 	return _exc_ref;
@@ -50,7 +50,7 @@
 	// Must be a Java object
 	jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
 	jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read__);
-	jobject _exc = go_seq_wrap_exception(env);
+	jobject _exc = go_seq_get_exception(env);
 	int32_t _exc_ref = go_seq_to_refnum(env, _exc);
 	jint _res = res;
 	go_seq_pop_local_frame(env);
@@ -63,7 +63,7 @@
 	// Must be a Java object
 	jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
 	jint res = (*env)->CallNonvirtualIntMethod(env, _this, class_java_io_InputStream, m_java_io_InputStream_read__);
-	jobject _exc = go_seq_wrap_exception(env);
+	jobject _exc = go_seq_get_exception(env);
 	int32_t _exc_ref = go_seq_to_refnum(env, _exc);
 	jint _res = res;
 	go_seq_pop_local_frame(env);
@@ -76,7 +76,7 @@
 	// Must be a Java object
 	jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
 	jobject res = (*env)->CallObjectMethod(env, _this, m_java_util_concurrent_Future_get__);
-	jobject _exc = go_seq_wrap_exception(env);
+	jobject _exc = go_seq_get_exception(env);
 	int32_t _exc_ref = go_seq_to_refnum(env, _exc);
 	jint _res = go_seq_to_refnum(env, res);
 	go_seq_pop_local_frame(env);
@@ -91,7 +91,7 @@
 	jlong _a0 = a0;
 	jobject _a1 = go_seq_from_refnum(env, a1, NULL, NULL);
 	jobject res = (*env)->CallObjectMethod(env, _this, m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2, _a0, _a1);
-	jobject _exc = go_seq_wrap_exception(env);
+	jobject _exc = go_seq_get_exception(env);
 	int32_t _exc_ref = go_seq_to_refnum(env, _exc);
 	jint _res = go_seq_to_refnum(env, res);
 	go_seq_pop_local_frame(env);
diff --git a/bind/testdata/classes.java.golden b/bind/testdata/classes.java.golden
index 2716ec9..40d4999 100644
--- a/bind/testdata/classes.java.golden
+++ b/bind/testdata/classes.java.golden
@@ -11,18 +11,18 @@
     
     private final Seq.Ref ref;
     
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
     Future(Seq.Ref ref) { this.ref = ref; }
     
     public Future() { this.ref = __New(); }
     
     private static native Seq.Ref __New();
     
-    @Override public final int incRefnum() {
-    	int refnum = ref.refnum;
-    	Seq.incGoRef(refnum);
-    	return refnum;
-    }
-    
     public final native java.util.concurrent.Future getFuture();
     public final native void setFuture(java.util.concurrent.Future v);
     
@@ -43,6 +43,12 @@
     
     private final Seq.Ref ref;
     
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
     public InputStream() {
         super();
         this.ref = __NewInputStream();
@@ -50,12 +56,6 @@
     
     private static native Seq.Ref __NewInputStream();
     
-    @Override public final int incRefnum() {
-    	int refnum = ref.refnum;
-    	Seq.incGoRef(refnum);
-    	return refnum;
-    }
-    
     public final native java.io.InputStream getInputStream();
     public final native void setInputStream(java.io.InputStream v);
     
@@ -75,18 +75,18 @@
     
     private final Seq.Ref ref;
     
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
     Object(Seq.Ref ref) { this.ref = ref; }
     
     public Object() { this.ref = __New(); }
     
     private static native Seq.Ref __New();
     
-    @Override public final int incRefnum() {
-    	int refnum = ref.refnum;
-    	Seq.incGoRef(refnum);
-    	return refnum;
-    }
-    
     public final native java.lang.Object getObject();
     public final native void setObject(java.lang.Object v);
     
@@ -105,18 +105,18 @@
     
     private final Seq.Ref ref;
     
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
     Runnable(Seq.Ref ref) { this.ref = ref; }
     
     public Runnable() { this.ref = __New(); }
     
     private static native Seq.Ref __New();
     
-    @Override public final int incRefnum() {
-    	int refnum = ref.refnum;
-    	Seq.incGoRef(refnum);
-    	return refnum;
-    }
-    
     public final native java.lang.Runnable getRunnable();
     public final native void setRunnable(java.lang.Runnable v);
     
diff --git a/bind/testdata/customprefix.objc.m.golden b/bind/testdata/customprefix.objc.m.golden
index f8f7425..5eae706 100644
--- a/bind/testdata/customprefix.objc.m.golden
+++ b/bind/testdata/customprefix.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "EXCustomprefix.h"
 
-static NSString* errDomain = @"go.customprefix";
-
 
 void EXCustomprefixF() {
 	proxycustomprefix__F();
diff --git a/bind/testdata/ignore.java.golden b/bind/testdata/ignore.java.golden
index b273056..7a90fde 100644
--- a/bind/testdata/ignore.java.golden
+++ b/bind/testdata/ignore.java.golden
@@ -6,10 +6,18 @@
 
 import go.Seq;
 
-public final class S extends Seq.Proxy implements I {
+public final class S implements Seq.Proxy, I {
     static { Ignore.touch(); }
     
-    S(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    S(Seq.Ref ref) { this.ref = ref; }
     
     // skipped field S.F with unsupported type: *types.Interface
     
@@ -75,9 +83,17 @@
     
     private static native void _init();
     
-    private static final class proxyI extends Seq.Proxy implements I {
-    	proxyI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI implements Seq.Proxy, I {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI(Seq.Ref ref) { this.ref = ref; }
+        
         // skipped method I.Argument with unsupported parameter or return types
         
         // skipped method I.Result with unsupported parameter or return types
diff --git a/bind/testdata/ignore.objc.h.golden b/bind/testdata/ignore.objc.h.golden
index 3515ac5..a47b512 100644
--- a/bind/testdata/ignore.objc.h.golden
+++ b/bind/testdata/ignore.objc.h.golden
@@ -55,7 +55,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 // skipped method I.Argument with unsupported parameter or return types
 
 // skipped method I.Result with unsupported parameter or return types
diff --git a/bind/testdata/ignore.objc.m.golden b/bind/testdata/ignore.objc.m.golden
index 57f1ba2..ed46739 100644
--- a/bind/testdata/ignore.objc.m.golden
+++ b/bind/testdata/ignore.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoIgnore.h"
 
-static NSString* errDomain = @"go.ignore";
-
 
 @implementation GoIgnoreS {
 }
@@ -31,7 +29,7 @@
 @implementation GoIgnoreI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
diff --git a/bind/testdata/interfaces.java.c.golden b/bind/testdata/interfaces.java.c.golden
index 71b12b5..1295730 100644
--- a/bind/testdata/interfaces.java.c.golden
+++ b/bind/testdata/interfaces.java.c.golden
@@ -124,7 +124,7 @@
     JNIEnv *env = go_seq_push_local_frame(0);
     jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_Error, proxy_class_interfaces_Error_cons);
     (*env)->CallVoidMethod(env, o, mid_Error_Err);
-    jobject exc = go_seq_wrap_exception(env);
+    jobject exc = go_seq_get_exception(env);
     int32_t _exc = go_seq_to_refnum(env, exc);
     go_seq_pop_local_frame(env);
     return _exc;
diff --git a/bind/testdata/interfaces.java.golden b/bind/testdata/interfaces.java.golden
index 5c49ed0..8164d15 100644
--- a/bind/testdata/interfaces.java.golden
+++ b/bind/testdata/interfaces.java.golden
@@ -124,45 +124,109 @@
     
     private static native void _init();
     
-    private static final class proxyError extends Seq.Proxy implements Error {
-    	proxyError(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyError implements Seq.Proxy, Error {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyError(Seq.Ref ref) { this.ref = ref; }
+        
         public native void err() throws Exception;
     }
-    private static final class proxyI extends Seq.Proxy implements I {
-    	proxyI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI implements Seq.Proxy, I {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI(Seq.Ref ref) { this.ref = ref; }
+        
         public native int rand();
     }
-    private static final class proxyI1 extends Seq.Proxy implements I1 {
-    	proxyI1(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI1 implements Seq.Proxy, I1 {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI1(Seq.Ref ref) { this.ref = ref; }
+        
         public native void j();
     }
-    private static final class proxyI2 extends Seq.Proxy implements I2 {
-    	proxyI2(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI2 implements Seq.Proxy, I2 {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI2(Seq.Ref ref) { this.ref = ref; }
+        
         public native void g();
     }
-    private static final class proxyI3 extends Seq.Proxy implements I3 {
-    	proxyI3(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI3 implements Seq.Proxy, I3 {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI3(Seq.Ref ref) { this.ref = ref; }
+        
         public native I1 f();
     }
-    private static final class proxyLargerI extends Seq.Proxy implements LargerI {
-    	proxyLargerI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyLargerI implements Seq.Proxy, LargerI {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyLargerI(Seq.Ref ref) { this.ref = ref; }
+        
         public native void anotherFunc();
         public native int rand();
     }
-    private static final class proxySameI extends Seq.Proxy implements SameI {
-    	proxySameI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxySameI implements Seq.Proxy, SameI {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxySameI(Seq.Ref ref) { this.ref = ref; }
+        
         public native int rand();
     }
-    private static final class proxyWithParam extends Seq.Proxy implements WithParam {
-    	proxyWithParam(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyWithParam implements Seq.Proxy, WithParam {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyWithParam(Seq.Ref ref) { this.ref = ref; }
+        
         public native void hasParam(boolean p0);
     }
     
diff --git a/bind/testdata/interfaces.objc.h.golden b/bind/testdata/interfaces.objc.h.golden
index 4464d81..171c519 100644
--- a/bind/testdata/interfaces.objc.h.golden
+++ b/bind/testdata/interfaces.objc.h.golden
@@ -36,7 +36,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)j;
 @end
 
@@ -44,7 +44,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)g;
 @end
 
@@ -87,7 +87,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (BOOL)err:(NSError**)error;
 @end
 
@@ -95,7 +95,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (int32_t)rand;
 @end
 
@@ -103,7 +103,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (GoInterfacesI1*)f;
 @end
 
@@ -111,7 +111,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)anotherFunc;
 - (int32_t)rand;
 @end
@@ -120,7 +120,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (int32_t)rand;
 @end
 
@@ -128,7 +128,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)hasParam:(BOOL)p0;
 @end
 
diff --git a/bind/testdata/interfaces.objc.m.golden b/bind/testdata/interfaces.objc.m.golden
index 47ccc23..4b7d5d4 100644
--- a/bind/testdata/interfaces.objc.m.golden
+++ b/bind/testdata/interfaces.objc.m.golden
@@ -8,12 +8,10 @@
 #include "_cgo_export.h"
 #include "GoInterfaces.h"
 
-static NSString* errDomain = @"go.interfaces";
-
 @implementation GoInterfacesError {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -31,7 +29,7 @@
 		}
 	}
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
@@ -42,7 +40,7 @@
 @implementation GoInterfacesI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -61,7 +59,7 @@
 @implementation GoInterfacesI1 {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -78,7 +76,7 @@
 @implementation GoInterfacesI2 {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -95,7 +93,7 @@
 @implementation GoInterfacesI3 {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -121,7 +119,7 @@
 @implementation GoInterfacesLargerI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -145,7 +143,7 @@
 @implementation GoInterfacesSameI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -164,7 +162,7 @@
 @implementation GoInterfacesWithParam {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -211,7 +209,7 @@
 		}
 	}
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
@@ -236,7 +234,7 @@
 		BOOL returnVal = [o err:&error];
 		id<GoUniverseerror> _error = nil;
 		if (!returnVal) {
-			_error = [[goSeqErrorWrapper alloc] initWithError:error];
+			_error = error;
 		}
 		int32_t __error;
 		if ([(id<NSObject>)(_error) isKindOfClass:[GoUniverseerror class]]) {
diff --git a/bind/testdata/issue10788.java.golden b/bind/testdata/issue10788.java.golden
index 4f23190..08d15f6 100644
--- a/bind/testdata/issue10788.java.golden
+++ b/bind/testdata/issue10788.java.golden
@@ -6,10 +6,18 @@
 
 import go.Seq;
 
-public final class TestStruct extends Seq.Proxy {
+public final class TestStruct implements Seq.Proxy {
     static { Issue10788.touch(); }
     
-    TestStruct(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    TestStruct(Seq.Ref ref) { this.ref = ref; }
     
     public final native String getValue();
     public final native void setValue(String v);
@@ -78,9 +86,17 @@
     
     private static native void _init();
     
-    private static final class proxyTestInterface extends Seq.Proxy implements TestInterface {
-    	proxyTestInterface(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyTestInterface implements Seq.Proxy, TestInterface {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyTestInterface(Seq.Ref ref) { this.ref = ref; }
+        
         public native void doSomeWork(TestStruct s);
         public native void multipleUnnamedParams(long p0, String p1, long p2);
     }
diff --git a/bind/testdata/issue10788.objc.h.golden b/bind/testdata/issue10788.objc.h.golden
index 7ef26c0..25c2e7d 100644
--- a/bind/testdata/issue10788.objc.h.golden
+++ b/bind/testdata/issue10788.objc.h.golden
@@ -33,7 +33,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)doSomeWork:(GoIssue10788TestStruct*)s;
 - (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 p2:(int64_t)p2;
 @end
diff --git a/bind/testdata/issue10788.objc.m.golden b/bind/testdata/issue10788.objc.m.golden
index dfdf093..80fc8a5 100644
--- a/bind/testdata/issue10788.objc.m.golden
+++ b/bind/testdata/issue10788.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoIssue10788.h"
 
-static NSString* errDomain = @"go.issue10788";
-
 
 @implementation GoIssue10788TestStruct {
 }
@@ -38,7 +36,7 @@
 @implementation GoIssue10788TestInterface {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
diff --git a/bind/testdata/issue12328.java.golden b/bind/testdata/issue12328.java.golden
index 1afcc1d..3dd20f9 100644
--- a/bind/testdata/issue12328.java.golden
+++ b/bind/testdata/issue12328.java.golden
@@ -6,10 +6,18 @@
 
 import go.Seq;
 
-public final class T extends Seq.Proxy {
+public final class T implements Seq.Proxy {
     static { Issue12328.touch(); }
     
-    T(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    T(Seq.Ref ref) { this.ref = ref; }
     
     public final native java.lang.Exception getErr();
     public final native void setErr(java.lang.Exception v);
diff --git a/bind/testdata/issue12328.objc.m.golden b/bind/testdata/issue12328.objc.m.golden
index 66969f4..7c5b8c0 100644
--- a/bind/testdata/issue12328.objc.m.golden
+++ b/bind/testdata/issue12328.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoIssue12328.h"
 
-static NSString* errDomain = @"go.issue12328";
-
 
 @implementation GoIssue12328T {
 }
diff --git a/bind/testdata/issue12403.java.c.golden b/bind/testdata/issue12403.java.c.golden
index cbb99ff..b641ba9 100644
--- a/bind/testdata/issue12403.java.c.golden
+++ b/bind/testdata/issue12403.java.c.golden
@@ -60,7 +60,7 @@
     jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue12403_Parsable, proxy_class_issue12403_Parsable_cons);
     jstring res = (*env)->CallObjectMethod(env, o, mid_Parsable_ToJSON);
     nstring _res = go_seq_from_java_string(env, res);
-    jobject exc = go_seq_wrap_exception(env);
+    jobject exc = go_seq_get_exception(env);
     int32_t _exc = go_seq_to_refnum(env, exc);
     cproxyissue12403_Parsable_ToJSON_return sres = {
     	_res, _exc
diff --git a/bind/testdata/issue12403.java.golden b/bind/testdata/issue12403.java.golden
index 30976be..50c81af 100644
--- a/bind/testdata/issue12403.java.golden
+++ b/bind/testdata/issue12403.java.golden
@@ -33,9 +33,17 @@
     
     private static native void _init();
     
-    private static final class proxyParsable extends Seq.Proxy implements Parsable {
-    	proxyParsable(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyParsable implements Seq.Proxy, Parsable {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyParsable(Seq.Ref ref) { this.ref = ref; }
+        
         public native String fromJSON(String jstr);
         public native String toJSON() throws Exception;
     }
diff --git a/bind/testdata/issue12403.objc.h.golden b/bind/testdata/issue12403.objc.h.golden
index 5b9f310..14c7dad 100644
--- a/bind/testdata/issue12403.objc.h.golden
+++ b/bind/testdata/issue12403.objc.h.golden
@@ -23,7 +23,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (NSString*)fromJSON:(NSString*)jstr;
 - (BOOL)toJSON:(NSString**)ret0_ error:(NSError**)error;
 @end
diff --git a/bind/testdata/issue12403.objc.m.golden b/bind/testdata/issue12403.objc.m.golden
index 4a06e15..c453a52 100644
--- a/bind/testdata/issue12403.objc.m.golden
+++ b/bind/testdata/issue12403.objc.m.golden
@@ -8,12 +8,10 @@
 #include "_cgo_export.h"
 #include "GoIssue12403.h"
 
-static NSString* errDomain = @"go.issue12403";
-
 @implementation GoIssue12403Parsable {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -41,7 +39,7 @@
 	}
 	*ret0_ = _ret0_;
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
@@ -69,7 +67,7 @@
 		nstring _ret0_ = go_seq_from_objc_string(ret0_);
 		id<GoUniverseerror> _error = nil;
 		if (!returnVal) {
-			_error = [[goSeqErrorWrapper alloc] initWithError:error];
+			_error = error;
 		}
 		int32_t __error;
 		if ([(id<NSObject>)(_error) isKindOfClass:[GoUniverseerror class]]) {
diff --git a/bind/testdata/java.java.golden b/bind/testdata/java.java.golden
index 3948a2b..74d9694 100644
--- a/bind/testdata/java.java.golden
+++ b/bind/testdata/java.java.golden
@@ -71,23 +71,55 @@
     
     private static native void _init();
     
-    private static final class proxyF extends Seq.Proxy implements F {
-    	proxyF(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyF implements Seq.Proxy, F {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyF(Seq.Ref ref) { this.ref = ref; }
+        
     }
-    private static final class proxyO extends Seq.Proxy implements O {
-    	proxyO(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyO implements Seq.Proxy, O {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyO(Seq.Ref ref) { this.ref = ref; }
+        
         // skipped method O.Super with unsupported parameter or return types
         
     }
-    private static final class proxyR extends Seq.Proxy implements R {
-    	proxyR(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyR implements Seq.Proxy, R {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyR(Seq.Ref ref) { this.ref = ref; }
+        
     }
-    private static final class proxyS extends Seq.Proxy implements S {
-    	proxyS(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyS implements Seq.Proxy, S {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyS(Seq.Ref ref) { this.ref = ref; }
+        
         // skipped method S.Super with unsupported parameter or return types
         
     }
diff --git a/bind/testdata/keywords.java.golden b/bind/testdata/keywords.java.golden
index b7f5ea1..04e7cb4 100644
--- a/bind/testdata/keywords.java.golden
+++ b/bind/testdata/keywords.java.golden
@@ -84,9 +84,17 @@
     
     private static native void _init();
     
-    private static final class proxyKeywordCaller extends Seq.Proxy implements KeywordCaller {
-    	proxyKeywordCaller(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyKeywordCaller implements Seq.Proxy, KeywordCaller {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyKeywordCaller(Seq.Ref ref) { this.ref = ref; }
+        
         public native void abstract_();
         public native void assert_();
         public native void boolean_();
diff --git a/bind/testdata/keywords.objc.h.golden b/bind/testdata/keywords.objc.h.golden
index df4c914..1cbdf7d 100644
--- a/bind/testdata/keywords.objc.h.golden
+++ b/bind/testdata/keywords.objc.h.golden
@@ -74,7 +74,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)abstract;
 - (void)assert;
 - (void)boolean;
diff --git a/bind/testdata/keywords.objc.m.golden b/bind/testdata/keywords.objc.m.golden
index d4f9d73..837ce6d 100644
--- a/bind/testdata/keywords.objc.m.golden
+++ b/bind/testdata/keywords.objc.m.golden
@@ -8,12 +8,10 @@
 #include "_cgo_export.h"
 #include "GoKeywords.h"
 
-static NSString* errDomain = @"go.keywords";
-
 @implementation GoKeywordsKeywordCaller {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
diff --git a/bind/testdata/structs.java.golden b/bind/testdata/structs.java.golden
index 61402a3..306f597 100644
--- a/bind/testdata/structs.java.golden
+++ b/bind/testdata/structs.java.golden
@@ -6,10 +6,18 @@
 
 import go.Seq;
 
-public final class S extends Seq.Proxy {
+public final class S implements Seq.Proxy {
     static { Structs.touch(); }
     
-    S(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    S(Seq.Ref ref) { this.ref = ref; }
     
     public final native double getX();
     public final native void setX(double v);
@@ -58,10 +66,18 @@
 
 import go.Seq;
 
-public final class S2 extends Seq.Proxy implements I {
+public final class S2 implements Seq.Proxy, I {
     static { Structs.touch(); }
     
-    S2(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    S2(Seq.Ref ref) { this.ref = ref; }
     
     public native void m();
     public native String string();
@@ -116,9 +132,17 @@
     
     private static native void _init();
     
-    private static final class proxyI extends Seq.Proxy implements I {
-    	proxyI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI implements Seq.Proxy, I {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI(Seq.Ref ref) { this.ref = ref; }
+        
         public native void m();
     }
     
diff --git a/bind/testdata/structs.objc.h.golden b/bind/testdata/structs.objc.h.golden
index 1512cf7..8a911bc 100644
--- a/bind/testdata/structs.objc.h.golden
+++ b/bind/testdata/structs.objc.h.golden
@@ -50,7 +50,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 - (void)m;
 @end
 
diff --git a/bind/testdata/structs.objc.m.golden b/bind/testdata/structs.objc.m.golden
index e48173e..b66a3e3 100644
--- a/bind/testdata/structs.objc.m.golden
+++ b/bind/testdata/structs.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoStructs.h"
 
-static NSString* errDomain = @"go.structs";
-
 
 @implementation GoStructsS {
 }
@@ -67,7 +65,7 @@
 	}
 	*ret0_ = _ret0_;
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
@@ -108,7 +106,7 @@
 @implementation GoStructsI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
@@ -170,7 +168,7 @@
 	}
 	*ret0_ = _ret0_;
 	if (_error != nil && error != nil) {
-		*error = go_seq_to_nserror(_error, errDomain);
+		*error = _error;
 	}
 	return (_error == nil);
 }
diff --git a/bind/testdata/try.objc.m.golden b/bind/testdata/try.objc.m.golden
index 9750654..0a0c03c 100644
--- a/bind/testdata/try.objc.m.golden
+++ b/bind/testdata/try.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoTry.h"
 
-static NSString* errDomain = @"go.try";
-
 
 NSString* GoTryThis() {
 	nstring r0 = proxytry__This();
diff --git a/bind/testdata/vars.java.golden b/bind/testdata/vars.java.golden
index 665910c..c66da14 100644
--- a/bind/testdata/vars.java.golden
+++ b/bind/testdata/vars.java.golden
@@ -6,10 +6,18 @@
 
 import go.Seq;
 
-public final class S extends Seq.Proxy implements I {
+public final class S implements Seq.Proxy, I {
     static { Vars.touch(); }
     
-    S(Seq.Ref ref) { super(ref); }
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    S(Seq.Ref ref) { this.ref = ref; }
     
     @Override public boolean equals(Object o) {
         if (o == null || !(o instanceof S)) {
@@ -63,9 +71,17 @@
     
     private static native void _init();
     
-    private static final class proxyI extends Seq.Proxy implements I {
-    	proxyI(Seq.Ref ref) { super(ref); }
-    
+    private static final class proxyI implements Seq.Proxy, I {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyI(Seq.Ref ref) { this.ref = ref; }
+        
     }
     
     
diff --git a/bind/testdata/vars.objc.h.golden b/bind/testdata/vars.objc.h.golden
index e1f45b8..4f15bc7 100644
--- a/bind/testdata/vars.objc.h.golden
+++ b/bind/testdata/vars.objc.h.golden
@@ -68,7 +68,7 @@
 }
 @property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref;
+- (instancetype)initWithRef:(id)ref;
 @end
 
 #endif
diff --git a/bind/testdata/vars.objc.m.golden b/bind/testdata/vars.objc.m.golden
index 7331d71..8a69fb3 100644
--- a/bind/testdata/vars.objc.m.golden
+++ b/bind/testdata/vars.objc.m.golden
@@ -8,8 +8,6 @@
 #include "_cgo_export.h"
 #include "GoVars.h"
 
-static NSString* errDomain = @"go.vars";
-
 
 @implementation GoVarsS {
 }
@@ -25,7 +23,7 @@
 @implementation GoVarsI {
 }
 
-- (id)initWithRef:(id)ref {
+- (instancetype)initWithRef:(id)ref {
 	self = [super init];
 	if (self) { __ref = ref; }
 	return self;
diff --git a/bind/testpkg/testpkg.go b/bind/testpkg/testpkg.go
index a812e9e..091b640 100644
--- a/bind/testpkg/testpkg.go
+++ b/bind/testpkg/testpkg.go
@@ -537,3 +537,13 @@
 type Issue17073 interface {
 	OnError(err error)
 }
+
+func ErrorMessage(err error) string {
+	return err.Error()
+}
+
+var GlobalErr error = errors.New("global err")
+
+func IsGlobalErr(err error) bool {
+	return GlobalErr == err
+}