Skip to content

Instantly share code, notes, and snippets.

@creachadair
Created July 22, 2023 22:05
Show Gist options
  • Save creachadair/e6b75324cf20745701cfc4bb8296171e to your computer and use it in GitHub Desktop.
Save creachadair/e6b75324cf20745701cfc4bb8296171e to your computer and use it in GitHub Desktop.
Checking type parameters for optional interface satisfaction in Go

Checking Type Parameters for Optional Interface Satisfaction

With Go generics, it is not permitted to check whether a value whose type comes from a type parameter satisfies some optional interface. For example, the following code will not compile (as of Go 1.20):

type Q interface{ Q() }

func G[T any](t T) {
	if q, ok := t.(Q); ok {
		q.Q()
		fmt.Println("Q", q)
	}
	fmt.Println("G", t)
}

Specifically, the compiler complains:

invalid operation: cannot use type assertion on type parameter value t (variable of type T constrained by any)

This follows from the definition at Type Assertions which says (emphasis mine):

For an expression x of interface type, but not a type parameter, and a type T, the primary expression x.(T) asserts that x is not nil and that the value stored in x is of type T. […] If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.

The exemption of type parameters permits the compiler to reject x whose type comes from a type parameter.

We can work around this, however, by introducing a temporary variable that is of interface type:

func F[T any](t T) {
	var v any = t  // v is type any, not just a type constrained by any

	if q, ok := v.(Q); ok {  // N.B. type assertion is on v
		q.Q()
		fmt.Println("Q", q)
	}
	fmt.Println("F", t)
}

This example demonstrates that this version correctly handles both a type that implements the optional Q interface, and one that does not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment