[generics] slightly surprising syntax for *T methods

190 views
Skip to first unread message

Sebastien Binet

unread,
Jun 17, 2020, 3:09:37 AM6/17/20
to golang-nuts
hi there,

I was playing a bit w/ pointer methods[1] to see how this could be applied to a pet peeve of mine: ensuring at compile-time that, e.g., json.Decoder.Decode takes a pointer to a value:

https://go2goplay.golang.org/p/J2Lr5QrkKTj

this works:

func Decode(type *T)(ptr *T) error {
return json.NewDecoder(new(bytes.Buffer)).Decode(ptr)
}

func main() {
var v int
Decode(int)(&v)
}

as well as this:

type Decoder(type *T) struct{}

func (dec *Decoder(T)) Decode(ptr *T) error {
// ...
return nil
}

func main() {
var v int
dec := Decoder(int){}
dec.Decode(&v)
}

but I was initially caught off guard trying to write the method on Decoder like so:

// ERROR: receiver type parameter *T must be an identifier
func (dec *Decoder(*T)) Decode(ptr *T) error {
return nil
}

(notice the extra '*' in Decoder(*T))

perhaps something to mention in the document?

-s

[1]: https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#pointer-methods



Sebastien Binet

unread,
Jun 17, 2020, 3:46:54 AM6/17/20
to golang-nuts
for completeness' sake, there is indeed no need for pointer methods:

https://go2goplay.golang.org/p/1WD7WRAmNim

(my main point was the gotcha w/ 'func (dec *Decoder(*T)) F()')




‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Wednesday, June 17, 2020 9:08 AM, Sebastien Binet <d...@sbinet.org> wrote:

> hi there,
>
> I was playing a bit w/ pointer methods[1] to see how this could be applied to a pet peeve of mine: ensuring at compile-time that, e.g., json.Decoder.Decode takes a pointer to a value:
>
> https://go2goplay.golang.org/p/J2Lr5QrkKTj
>
> this works:
>
> func Decode(type *T)(ptr *T) error {
> return json.NewDecoder(new(bytes.Buffer)).Decode(ptr)
> }
>
> func main() {
> var v int
> Decode(int)(&v)
> }
>
> as well as this:
>
> type Decoder(type *T) struct{}
>
> func (dec *Decoder(T)) Decode(ptr *T) error {
> // ...
> return nil
> }
>
> func main() {
> var v int
> dec := Decoder(int){}
> dec.Decode(&v)
> }
>
> but I was initially caught off guard trying to write the method on Decoder like so:
>
> // ERROR: receiver type parameter *T must be an identifier
> func (dec *Decoder(*T)) Decode(ptr T) error {
> return nil
> }
> (notice the extra '' in Decoder(*T))

Ian Lance Taylor

unread,
Jun 19, 2020, 8:13:35 PM6/19/20
to Sebastien Binet, golang-nuts
Using a pointer method, as in "type *T", does not mean that the type
argument must be a pointer. If you write "(type *T C)", it means
that, given a type argument A, the type *A must implement the
constraint C. There is actually no reason to ever write "(type *T)"
with no constraint. That means that, given a type argument A, the
type *A must implement the empty constraint, which it does, because
all types implement the empty constraint.

Pointer methods do seem to be confusing. I think they have a clear
use, but it may be that they are too confusing for that use.

Ian

Sebastien Binet

unread,
Jun 20, 2020, 4:25:21 AM6/20/20
to ia...@golang.org, golan...@googlegroups.com
Ian,

Thanks for your reply.

Yes, it's just probably because it's still early days but I was a bit confused.

Happy to note this new draft allows to define functions (and methods) that can only take pointers to values, though.

-s






-------- Original Message --------
Reply all
Reply to author
Forward
0 new messages