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/go2go: Recursive generics hang the playground. #39688
Comments
At the moment it doesn't hang on the dev.go2go branch, but it also doesn't build. I don't really see how it could ever build. |
This type-checks now on the dev.go2go branch and it also runs if the $ go tool go2go run main.go2
Foo: {0 {0 {0 {}}}}!
{7 {}} When the
I fail to see at the moment what's wrong with the |
Well I'm not sure if this type of recursion should be allowed, I was just trying to play around and see if I could implement compile time Lisp-like lists using generics. But if it is allowed then it should of course also work correctly. |
Change https://golang.org/cl/239137 mentions this issue: |
The Probably the type checker should catch this. We have a rule saying that a generic type can't refer to itself with different arguments. That rule has to apply not just to the body of the type, but also to the methods of the type. In this case I think the The translator had a bug that caused the infinite loop to terminate, generating code that had a type error. I've fixed that bug, and I've introduced a type instantiation loop check, so now this test case will fail with the translator reporting an infinite loop. Reassigning to @griesemer to decide whether he should implement the suggested check for a recursive type reference. |
It's not correct to do it here, as we aren't instantiating this particular type. Also had a loop check to avoid endless instantiating a recursive type. Fixes #39688 Change-Id: Ief4c57bb5cea3013501e33ab5bc82a29707af5be Reviewed-on: https://go-review.googlesource.com/c/go/+/239137 Reviewed-by: Ian Lance Taylor <iant@golang.org>
The interesting thing, though, it that if works as a function, at least for one level of tuples, though not for two levels, where the translator fails. package main
import (
"fmt"
)
type Nil struct {
}
type Tuple(type A, B) struct {
A A
B B
}
func (u Tuple(A,B)) Head() A {
return u.A
}
func (u Tuple(A,B)) Tail() B {
return u.B
}
func New(type A,B)(a A, b B) Tuple(A, B) {
return Tuple(A, B){a, b}
}
func AppendTuple(type A, B)(u Tuple(A,B), v B) Tuple(Tuple(A,B), B) {
return Tuple(Tuple(A,B), B){u, v}
}
func NewList(type T)(v T) Tuple(Nil,T) {
return Tuple(Nil, T){Nil{},v}
}
func main() {
t := Tuple(int,Tuple(int,Tuple(int,Nil))){}
l := NewList(7)
l2 := AppendTuple(l, 8)
// l3:= AppendTuple(Tuple(Nil,int), int)(l2, 9)
fmt.Printf("Foo: %v!\n%v\n%v\n", t, l, l2)
} It would be nice if it worked at least as a function, also at depths greater than 1. |
@beoran The test case in #39688 (comment) works for me using the current dev.go2go branch. The playground is probably not yet up to date with the latest changes. |
Ok, that's great. However, this does lead me to this question: Why can it work with a function but not with a method? We could probably break the recursion in the method case by treating it as if it was a function. |
If you instantiate But that has an The function not being directly bound to the type avoids this loop. It only needs to be instantiated when called. |
Thanks for the explanation, however, I fail to see why the method has to be instantiated on definition while the function is instantiated on call. Should generic methods not also be instantiated on call? |
Methods are part of the type. |
Hmm, yes that is right. If we consider it like that, recursion in methods should not be allowed by the type checker. It does mean that lisp like lists will likely be possible at compile time using functions. Does this make the Go generics Turing complete, and is that desirable? |
It is not desirable that Go generics be Turing complete. If you are able to demonstrate that, please do share it. Thanks. |
I tried to see if the generics themselves could be made Turing complete, based on C++, but because there is no partial template instantiation, and type arguments may not be a variable arugment list, which makes it more difficult with this generics proposal than with C++ for generics to be Turing complete at compile time. However, I found this article on Java that may be relevant: https://arxiv.org/pdf/1605.05274.pdf . It shows that the Java generic type checker is Turing complete. I wasn't able to construct the same in Go yet, but it might be that constrains suffer from the same problem. |
The result for Java seems to hinge on covariant typing, which Go does not support with or without the generics described in the design draft, so I'm not too worried. |
No longer relevant |
I tried this on the playground:
But it hung the playground instance I was working on indefinitely without crashing. Hopefully it didn't break anything serious, a new instance of the pleyground seems ok. I'm not sure if such recursion as in Append should be allowed or not, although it would be handy. If not, then the recursion should e detected promptly somehow to prevent such hangs.
The text was updated successfully, but these errors were encountered: