-
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
cmd/compile: seemingly valid generic interface rejected #68162
Comments
Similar Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
Your playground example asserts that it is not possible to factor
into
But this definition seems to fit the bill:
https://go.dev/play/p/nqgWVreqDoW?v=gotip Maybe i'm missing something but i'm not sure why Element's type argument would need to itself be constrained by Element. That does seem troublesomely recursive. |
If Go had a Self type, you could write something like this and avoid needing to pass E to Element as an argument, but of course it doesn't.
|
I think the most relevant comparison is with something that does work already, which is not naming the constraint:
|
I believe this is a duplicate of #63149. |
Firstly, you can't create yourself, and secondly, you don't exist yet. |
This kind of recursive constraint is needed to be able to express interfaces that reference types that in turn have type parameters with the same constraint. For instance: type ElementList[E Element[E]] []E
func (el ElementList[_]) IsSorted() bool {
for i := 0; i < len(el) - 1; i++ {
// E must be Element to be able to call Less()
if !el[i].Less(el[i+1]) {
return false
}
}
return true
}
type Element[E Element[E]] interface {
Less(E) bool
Children() ElementList[E] // E must be Element
} The limitation discussed in this issue currently makes it impossible to define an interface like this. I've run into this limitation multiple times, in particular in the context of self-descriptive types, i.e. types that model themselves - for example, a type that holds data from a database and also has methods that describe what fields correspond to what database columns, how the type relates to other types, etc. That often leads to this kind of recursive constraint and has resulted in a lot of refactoring to work around, generally having to make tradeoffs in regards to how ergonomic the API is, requiring more boilerplate or auxiliary types for the API user. |
@magical Thanks for pointing this out. I missed that while hastily writing this up so as not to forget about it before leaving for home. That said, there may still be situations where the circularity might be needed (see @arvidfm's example); and more generally there's a question as to whether there's a more principal reason why such declarations should or should not be valid. @zephyrtronium Thanks for finding the duplicate #63149. Leaving both open for now to capture both discussions. @arvidfm Just to be clear, the only thing that doesn't work in your example is the |
@griesemer Indeed. Thank you @arvidfm for the example. I can see how mutually-recursive types would cause more difficulties. The self-recursive case seems much less compelling on its own since it seems easy to eliminate the recursion by hand. |
Change https://go.dev/cl/605755 mentions this issue: |
I don't see a good reason why the following interface should be invalid:
Yet the compiler reports an invalid recursive type.
See example application here.
The text was updated successfully, but these errors were encountered: