Go version

go1.25rc1

Output of go env in your module/workspace:

n/a

What did you do?

Run the following program:

var v error
rv := reflect.ValueOf(&v).Elem()
v1, ok1 := rv.Interface().(error)
fmt.Println(v1, ok1)
v2, ok2 := reflect.TypeAssert[error](rv)
fmt.Println(v2, ok2)

What did you see happen?

This prints:

<nil> false
<nil> true

What did you expect to see?

As currently documented, TypeAssert[T](v) is semantically identical to v.Interface().(T).

If so, this should print:

<nil> false
<nil> false

We should either: 1. Fix the implementation of TypeAssert to match the documented behavior. 2. Fix the documentation of TypeAssert that it handles nil interface values.

I don't feel strongly what we should do. The advantage of option1 is that the documented semantics is simple, but the advantage of 2 is that it more correctly matches what is going on under-the-hood. An argument for option 2 is that TypeFor is not the same as TypeOf when it comes to interface values. Thus, one could argue that divergence in behavior just for interfaces is reasonable. In this particular case, the divergence is limited to just nil interface values, which is an even smaller divergence.

Comment From: mateusz834

I still wonder whether TypeAsseet should be identical to .Interface().(T), given all of these corner cases. They are really hard to think about, just by looking at the generic signature of TypeAssert.

In https://github.com/golang/go/issues/62121#issuecomment-2649244345 you mentioned that:

it's very easy to explain TypeAssert being equivalent to v2, ok := v.Interface().(T).

But it is also easy to explain that it allows converting val to a concrete type when v.Type() == TypeFor[T]().

Comment From: dsnet

given all of these corner cases

What other corner cases are you thinking of?

I was reading through the discussion in the proposal again and @ianlancetaylor said:

The goal is for the reflect package to more or less duplicate the language. Since the language permits type assertions to interface types, I would expect reflect.TypeAssert to do the same.

I'm inclined to agree, which seems to suggest we go with option 2 of documenting that it exactly matches the Go language type assertion operator (which it is named after).

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: mateusz834

What other corner cases are you thinking of?

I am thinking about all the cases from:

https://github.com/golang/go/blob/0f8ab2db177baee7b04182f5641693df3b212aa9/src/reflect/all_test.go#L8687

Where the types are different, but TypeAssert returns ok == true.

Comment From: mateusz834

I was reading through the discussion in the proposal again and @ianlancetaylor said:

The goal is for the reflect package to more or less duplicate the language. Since the language permits type assertions to interface types, I would expect reflect.TypeAssert to do the same.

I'm inclined to agree, which seems to suggest we go with option 2 of documenting that it exactly matches the Go language type assertion operator (which it is named after).

Possibly it makes sense, that we should follow the language here, because of the name of that function - TypeAssert. But i remember that while implementing it, it was really hard for me to think about the test cases (in above messages), which also leads me to a conclusion that I would prefer having a func that extracts a value only if the types are identical, maybe if we changed the name to AssertTo[T]/ValueTo[T], then it would make sense?

Comment From: dmitshur

CC @golang/runtime.

Comment From: cherrymui

The language's type assert returns false for nil interface value, though: https://go.dev/play/p/USwKfZnSXL-

    var v error
    b, ok := v.(error)
    fmt.Println(b, ok) // nil, false

So if we go with "option 2" we'd also need to change the implementation. Or what you have in mind is a different way to match it to the language's type assert?

Comment From: dsnet

@cherrymui Ah, you're right! I was being confused. So making sure a nil interface value can't be asserted to the interface type will exactly match the behavior of the language anyways.

that extracts a value only if the types are identical

At least empirically looking at the many of the cases where this would be useful, supporting conversions from interfaces to concrete types and vice versa would be very useful.

Comment From: gopherbot

Change https://go.dev/cl/684675 mentions this issue: reflect: fix TypeAssert on nil interface values