-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: spec: allow type assertion on type parameter value #49206
Comments
CC @griesemer There was some discussion of this in the thread starting at https://groups.google.com/g/golang-nuts/c/iAD0NBz3DYw/m/VcXSK55XAwAJ which led to that part of the proposal being withdrawn. CC @rogpeppe I think it's probably too late to add this to 1.18 at this point. |
This thread seems to be referring to type switching on the constraint, not on a value with a generic type. I was assuming type switching on a value but being able to treat it as the final concrete type because only the correct branch would be compiled in and at this point there is no uncertainty about what type the value is. It's possible I misunderstood this about the original FAQ in the proposal as well. For example, I'd like to be able to do something like the following and have it work (with the type switch reduced to just the correct line at compile time):
It's possible this would need some different syntax ( |
Hi @SamWhited, is there some overlap with what you wrote in that quote with #45380? (And I happen to like this earlier example in #45346 (comment)). |
I don't see any particular reason why a type switch on a generic value couldn't be allowed (although the "reduced to just the correct line at compile time" aspect is an implementation detail and probably wouldn't be the case with the current GC-shape stenciling implementation). I'm biased of course, but I think that #45380 provides a nicer and more generally useful facility. For example, if |
Yes, that looks the same. Thanks for the link!
Yes, that's definitely the case. |
Placed on hold. |
Really we want to examine the type parameter though, not the variable, right?. Perhaps it would be more useful if we switched on the type parameter itself.
|
That's exactly what #45380 proposes. |
Not sure if this specific use case is part of a proposal (the issue trackers are a bit tricky to search through sometimes), but. Say I have these type constraints: type SignedInt interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type UnsignedInt interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
type BigInt interface {
~*big.Int
}
type MaybeBigInt interface {
BigInt | SignedInteger | UnsignedInteger
} And have a function which takes func CheckParseMaybeBigInt[T MaybeBigInt](val T) *big.Int {
...
} Currently I have to do a type switch using switch n := val.(type) {
case SignedInteger:
return big.NewInt(int64(n))
case UnsignedInteger
return new(big.Int).SetUint64(uint64(n))
case BigInt:
return n
} would be infinitely cleaner and far easier to code. |
I realize this is on hold, but FWIW started migrating a codebase to generics today and accidentally did a similar thing as mentioned in the description when using
|
This is a valid (hypothetical) Go code: type Left[T any] struct{ Value T }
type Right[T any] struct{ Value T }
type Either[T any, V any] interface{ Left[T] | Right[V] }
func action[T Either[int, string]](v T) {
switch ((any)(v)).(type) {
case Left[int]:
fmt.Println("Left")
case Right[string]:
fmt.Println("Right")
}
}
func sampleCall(v Left[int]) { action(v) } And it seems type assertion on func typeSwitchLab1(val interface{}) {
switch val.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
// case Either[int, string]: <- this is not valid
}
}
func typeSwitchLab2[T Either[int, string]](val T) {
/*
switch val.(type) { <- this is not valid
case Left[int]:
fmt.Println("Left")
case Right[string]:
fmt.Println("Right")
}
*/
} If type constraints participate in type switches, then type constraints will also be types (in that case, should all type parameters be already known/resolved?). I vouch neither for nor against this feature. I am just curious about the amount of its real-world usage and how it might change the current implementation (and how the added semantic complexity would look like). |
@dc0d I don't really understand your question. As you've shown, you can currently do a type switch on a generic value (https://go.dev/play/p/arj825wElvB) - your In your See this issue for a proposal that would allow putting a constraint in a type switch case: #45380. If that were implemented, you could do:
|
@rogpeppe As stated at the end, it was not a question. It was an "opinion" based on the speculated required changes needed for this feature (including re-scoping type constraints with multiple overloaded meaning/semantics - including type switching over type constraints and not just types). The amount of complexity and cognitive load added by this feature could surpass the value it provides. |
Hi all,
When using the Go 1.18 generics implementation I've found myself several times wishing I had compile time type assertions. When looking to see why these didn't exist I found the FAQ entry about it, which contains the following:
I started doing this as that's what was recommended, however I quickly ran into an issue: if I accidentally asserted on the wrong thing (ie the struct instead of a field, or the wrong field, etc.) this would result in a silent failure (no error, the type switch would just fail) because anything can be stuffed into an empty interface. In one concrete example I typed the following:
and was having trouble figuring out why my code was failing. What I had meant to type was
item.Value
or something along those lines which is a generic member of the struct, however, because anything could be boxed into an interface the code happily compiled and ran, resulting in fallback behavior even though I knew the type was correct (and confusing me for quite a while until I spotted the typo).If however compile time type switching and assertions existed this would have failed because item is not an interface type. I would have then realized my mistake and been able to fix it thanks to the nice error message. Another benefit is that at compile time the type switch or assertion could result in a compile error if one of the branches or the assertion was a value that does not meet the interface, adding a layer of compile time safety and reducing dead code, or possibly catching some accidental uses of the wrong type.
In just a few days of using generics on a real project I have run into this and similar issues several times, so I'd like to request that the lack of compile time assertions be reconsidered.
The other reason mentioned for not doing them is that it can be confusing which type we're asserting on:
However that confusion is not reduced by using a runtime type switch as evidenced by the example later on in this section where similar confusion occurs at runtime. I believe the potential for silent failures to be worse than the potential for confusion about the types (though that is entirely anecdotal based on a very limited amount of time using the most recent proposal for anything that's not just a toy).
I will volunteer to write a proper proposal if this is something the Go team is willing to reconsider in a future version of Go.
The text was updated successfully, but these errors were encountered: