Go version
go version go1.22.6 darwin/arm64
Output of go env
in your module/workspace:
-
What did you do?
Please see https://go.dev/play/p/gOQFnwKeKIV
The crux being:
func F1[T newableObject[U], U any](obj *T) {
fmt.Println("Inside F1", *obj, *obj == nil)
F2[T, U](*obj) // *obj == nil per the above, gets un-nilled in the child
F2[T, U](nil) // Passing nil directly retains the nil-ness
}
func F2[T newableObject[U], U any](obj object) {
fmt.Println("Inside F2", obj, obj == nil)
}
func main() {
var obj *S // nil
F1(&obj)
}
Inside F1 <nil> true
Inside F2 <nil> false
Inside F2 <nil> true
In essence, inside a generic method, a pointer to an interface can contain nil interface, but when passing that nil interface to another generics method, it gets turned into a non-nil interface containing nil. This is bad because the user's nil input gets turned into a non-nil-nil, for which there isn't even a cheap way to test against apart from using reflection.
What did you see happen?
A a nil interface gets turned into a non-nil-interface-containing-nil.
What did you expect to see?
I expect a nil-interface to retain it's nil-ness.
Comment From: gabyhelp
Related Issues and Documentation
- affected/package: interfaces with generics #50313 (closed)
- generics: nullability checks don't work on variables constrained to interface #54186 (closed)
- go/types, types2: Syntax (interface vs nil struct) This example breaks the concept of passing nil values to interface #54470 (closed)
- Method called with NIL pointer receiver when using interfaces #25496 (closed)
- Interface type variables cannot be compared with nil while holding nil pointer of interface implementation #13562 (closed)
- A nil passed to an interface parameter violates function signature #44978 (closed)
- nil empty interface conversion to generic type panics #57839 (closed)
- Can not return nil on generic type which is an interface, is that a bug? #69011 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: karalabe
FWIW, seems if I change the type of F2's obj from object
to T
it works correctly. This was a fault with me refactoring a previous code and keeping the interface type instead of using the generic one, but still, I find the behavior odd and would venture to say it's buggy?
Comment From: zephyrtronium
This is https://go.dev/doc/faq#nil_error. You have a non-nil interface containing nil. It may be surprising, but it is following the rules of the language.
Comment From: karalabe
@zephyrtronium The point is that the generics code converts a nil interface to a non-nil interface, whereas it shouldn't do such a thing. That's what the issue is about.
Comment From: randall77
I agree with @zephyrtronium, this is just how putting nil pointers in interfaces work. There is nothing that is converting a nil interface to a non-nil interface. There is something converting a variable whose type is a type parameter constrained by an interface, but that's not the same thing.
To be explicit about instantiations, the call to F1
is F1[*S, S](&obj)
. Inside that instantiation of F1
, T
and U
are not interface types.