Skip to content
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

types2, go/types: pseudo-specialization sometimes works, but not really #47419

Closed
4ad opened this issue Jul 27, 2021 · 3 comments
Closed

types2, go/types: pseudo-specialization sometimes works, but not really #47419

4ad opened this issue Jul 27, 2021 · 3 comments

Comments

@4ad
Copy link
Member

@4ad 4ad commented Jul 27, 2021

From the design document:

No specialization. There is no way to write multiple versions of a generic function that are designed to work with specific type arguments.

On latest commit 37d2219 of dev.typeparams branch this code compiles just fine:

type Bar[T any] struct{ v T }

func (b Bar[int]) bar() int { return b.v }

Is this an instance of specialization? This is the sole instance of the code, and it "works" (but see baz below). Should it be accepted?

Regardless, the following doesn't work:

type Foo[T any] struct{}

func (Foo[int]) foo() int { return 42 }

it fails with cannot use 42 (untyped int constant) as int value in return statement, which is a rather confusing error message.

Interestingly enough, this also doesn't work:

func (b Bar[int]) baz() int { return b.v + b.v }

the error in this case is invalid operation: operator + not defined on b.v (variable of type parameter type int).

@zikaeroh
Copy link
Contributor

@zikaeroh zikaeroh commented Jul 27, 2021

Unless I'm mistaken, this code:

type Bar[T any] struct{ v T }

func (b Bar[int]) bar() int { return b.v }

Is equivalent to:

type Bar[T any] struct{ v T }

func (b Bar[T]) bar() T { return b.v }

It compiles because you've used the name int for the type parameter in that method's scope; it's not being specialized to int, it's just a type variable that happens to be called int (and b.v is of the same type, though defined with a different name).

If I write:

type Bar[T any] struct{ v T }

func (b Bar[something]) bar() something { return 42 }

The error message is cannot use 42 (untyped int constant) as something value in return statement.

The return 42 example fails because 42 isn't compatible with struct{}, and the b.v + b.v example doesn't compile because + is not defined for any.

Loading

@4ad
Copy link
Member Author

@4ad 4ad commented Jul 27, 2021

Interesting. So type parameters in type definitions are universally quantified, but type indices (?) in method definitions act more like existentials. This is somewhat strange because type parameters in non-method functions are universals.

Loading

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jul 27, 2021

A definition like

func (b Bar[int]) bar() int { return b.v }

just means that for the body of the method, the type parameter is named int. It's no different from writing

func (b Bar[MyTypeParameterName]) bar() MyTypeParameterName { return b.v }

Remember that in Go int is not a keyword, it's just a predeclared identifier. Using it as a type parameter name in a method declaration shadows the predeclared definition.

Similarly, this is valid Go;

func F(int string) string { return int }

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants