However, there is no way for P to check if x is nil. This does not compile:
func P[T fmt.Stringer](x T) {
if x!=nil {
fmt.Println(x)
}
}
Is it possible to write a generic function that can test if its
argument with a constraint is nil?
The end result is there's a crucial but subtle difference between:type Foo interface { ... }func f(v Foo) ...andtype 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 betweenfunc f(a, b fmt.Stringer) c fmt.Stringer { ... }andfunc 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: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: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...@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.
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 betweenfunc f(a, b fmt.Stringer) c fmt.Stringer { ... }andfunc 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: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: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.
--
On Wed, Jan 20, 2021 at 11:08 AM Brian Candler <b.ca...@pobox.com> wrote:What I mean is, the difference betweenfunc f(a, b fmt.Stringer) c fmt.Stringer { ... }andfunc 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 only thing standing in the way of that is the requirement to enable operator usage. You can't use `+,<,*,…` on interface values, so if you require the design to support using them
And FWIW, the design intentionally doesn't imply implementation choice - that is, in general, a compiler should be free to choose a pure boxing implementation already and AFAIK that's how the prototype works. That boxing implementation is more complicated though, than simply "put things into interfaces", because you need to provide access to operators.
What do you make of this?Using interface values, it seems possible to bypass a declared constraint that two arguments have the same type.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/e4e446de-9be4-4e31-8df7-ed48998022een%40googlegroups.com.
Can you come up with a realistic reason to have that constraint that doesn't end up needing reflect anyway (where you can implement any checks you want)?
On Wednesday, 20 January 2021 at 11:53:23 UTC axel.wa...@googlemail.com wrote:Can you come up with a realistic reason to have that constraint that doesn't end up needing reflect anyway (where you can implement any checks you want)?Mainly it's programmer comfort. If I write a container which holds a type T then:1. I expect it to actually hold all values of the same type T, not a mixture of types A, B and C.2. I expect it not to hold 'nil' values which have no concrete type at allIf I was happy with the mixture of different types and/or nil values, then I could have just used an interface in the first place, not generics.
I would get this comfort if interface types were *not* allowed to instantiate a generic type.
However, it's all down to how the generic type is instantiated. I guess I can just ignore this, and assume nobody "abuses" my generic code by instantiating it with an interface type. As you said, this problem doesn't present for type lists, only for method interfaces.
--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/6a2eedda-47ea-4ab8-ab85-66239e3ec3bbn%40googlegroups.com.
What do you make of this?Using interface values, it seems possible to bypass a declared constraint that two arguments have the same type.