Generic type for struct method: constraint problem && cannot use (untyped string constant) as string value

894 views
Skip to first unread message

ahuigo

unread,
Nov 9, 2023, 8:09:59 PM11/9/23
to golang-nuts
There is an example: https://go.dev/play/p/guzOWRKi-yp

```
func (c *cachedFn[string, V]) Get0() (V, error) {
// var s any
var s string
s = "abc" // error: cannot use "abc" (untyped string constant) as string value in assignment
fmt.Printf("cache key: %#v, %T\n", s, s) // cache key: 0, uint8
return c.Get(s)
}
```
I find the generic type of the struct method a bit confusing.
1.  The type `cachedFn[string, V]` does not really constrain the type of  `s` to **string**. It's actual type is `uint8`
2. And this error is a bit strange. (`s = "abc"  // error: cannot use "abc" (untyped string constant) as string value in assignment. ` )


Axel Wagner

unread,
Nov 9, 2023, 8:34:46 PM11/9/23
to ahuigo, golang-nuts
Yes, this has come up before.

On Fri, Nov 10, 2023 at 7:09 AM ahuigo <a13...@gmail.com> wrote:
There is an example: https://go.dev/play/p/guzOWRKi-yp

```
func (c *cachedFn[string, V]) Get0() (V, error) {
// var s any
var s string
s = "abc" // error: cannot use "abc" (untyped string constant) as string value in assignment
fmt.Printf("cache key: %#v, %T\n", s, s) // cache key: 0, uint8
return c.Get(s)
}
```
I find the generic type of the struct method a bit confusing.
1.  The type `cachedFn[string, V]` does not really constrain the type of  `s` to **string**. It's actual type is `uint8`

The type `cachedVn[string, V]` *would* in fact instantiate `cachedVn` with `string` and `V`.
But that's not what you are doing. You are writing the receiver type as `fun c(c *cachedFn[string, V])`, which means that "the receiver is the generic type `cachedVn` with two type parameters called `string` and `V`".
Predeclared identifiers in Go are not special in any way, you can re-use them for your own variables and types - or type parameters. So what you are doing here is fundamentally similar to this problem: https://go.dev/play/p/lDE-o7fGHi8

There probably should be a vet check for using a predeclared identifier as a type parameter name (or maybe even for any re-use of a predeclared identifier).

2. And this error is a bit strange. (`s = "abc"  // error: cannot use "abc" (untyped string constant) as string value in assignment. ` )


--
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/58c92577-cb98-401a-978d-c22a1fb493ccn%40googlegroups.com.

ahuigo

unread,
Nov 10, 2023, 4:25:05 AM11/10/23
to golang-nuts
Btw, please ignore the type logic in my code, I wrote this piece of code just to illustrate the oddities of generics in struct methods.
Regardless of whether its type is int, string, any, or the exact uint8, this error is very strange.


// it doesn't work
func (c *cachedFn[uint8, V]) Get0() (V, error) {
var s uint8 = 0
s = 0 // error: cannot use 0 (untyped int constant) as uint8 value in assignment
fmt.Printf("cache key: %#v, %T\n", s, s) // cache key: 0, uint8
return c.Get(s)
}

// it works
func (c *cachedFn[uint8, V]) Get0() (V, error) {
var s uint8 = 0
fmt.Printf("cache key: %#v, %T\n", s, s) // cache key: 0, uint8
return c.Get(s)
}

tapi...@gmail.com

unread,
Nov 10, 2023, 6:17:22 AM11/10/23
to golang-nuts
The uint8 in cachedFn[uint8, V] is the type parameter name, it can be arbitrary valid identifier.
It shadows the predeclared uint8 identifier.

Axel Wagner

unread,
Nov 10, 2023, 7:25:14 AM11/10/23
to ahuigo, golang-nuts
I agree that it is an unfortunate error message, but to be clear, it is entirely correct - you are defining a new type called `uint8` and it is indeed not possible to assign an untyped integer constant to that, as its underlying type is a type parameter (constrained on any).

I'm pretty sure there already is an issue about this, though I can't come up with helpful search terms to look it up. But the short term fix is absolutely "don't define types with the same name as predeclared idenfiers".

Reply all
Reply to author
Forward
0 new messages