On Wednesday, 20 January 2021 at 03:06:43 UTC bbse...@gmail.com wrote: > Is it possible to write a generic function that can test if its > argument with a constraint is nil? >
I think there is a deeper question in there. In the Generics proposal, type constraints (other than type lists) take the form of interfaces. For example, a generic type T may be constrained with interface C. Question: if a function takes type T, does that permit *both* values of concrete types which implement C, *and* interface values which implement C? Apparently it does: https://go2goplay.golang.org/p/sVaW1YoXKf1 That, to me, is surprising at first. I write a generic function because I want it to be expanded for different concrete types; but then I am surprised to find it can also be used for dynamic runtime types. In principle, I guess it shouldn't really matter, since whatever type is provided has the expected behaviour. Except: as the OP observed, interface types have the ability to be "nil", which concrete types don't (bar pointers/slices). The end result is there's a crucial but subtle difference between: type Foo interface { ... } func f(v Foo) ... and type Foo interface { ... } func f[T Foo](v T) ... Given that the second case supports both concrete types *and* interface types, then it seems to me that comparing a value with nil is a semantically valid thing to do. If the function specialisation is a concrete type, then that comparison would always be false and the code path optimised out. Alternatively, generics could exclude interface values. But then you get the weird situation that a generic function declaration that *looks* like an interface type, explicitly disallows interface type values! ---- 8< ---- With my wild hat on: it makes me wonder what would happen if the generics proposal became nothing more than interfaces with linked constraints - so that you could say "this function takes a function of type T (interface C) and returns *the same type* T", or "this function takes a []T and returns a value of *the same type* T". What I mean is, the difference between func f(a, b fmt.Stringer) c fmt.Stringer { ... } and func f[T fmt.Stringer](a, b T) c T { ... } would simply be that a, b and c had to be of the *same* concrete type - but were otherwise still interface values (and specialisation, if implemented, would just be a hidden optimisation). The obvious problem is that if you actually pass interface values around, then many type-mismatch violations couldn't be detected until runtime. However: I find the same problem occurs with the current generics implementation, *if* you pass interface variables. Check this out: https://go2goplay.golang.org/p/F08gh5gotsO Print2() expects that both arguments are of the same type - but in the final call, they are not! There is neither compile-time nor run-time error. ISTM that constrained interface types *could* also be checked at compile time, in the common case where the caller passes concrete types. Rewriting to use plain interfaces instead of generics: https://go2goplay.golang.org/p/CfkvAcgr8mC I think that an interface type constraint system *could* statically check that both args of the first Print2() call were (or were not) the same type. What you might end up with is linked type constraints being a natural extension of interfaces. Generic specialisation would just be an optimisation on top of that (if the call site knows that a particular set of concrete types is being used). Type lists could also become an extension of interfaces. However, that's just off the top of my head. Whilst I've been following generics intermittently, no doubt this has been considered (and discarded) before. Regards, Brian. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/34bdb40e-ad0b-47ce-8588-d014d0886470n%40googlegroups.com.