automatic referencing of structs vs interface

15 views
Skip to first unread message

eadfrith

unread,
Nov 25, 2009, 4:40:33 PM11/25/09
to golang-nuts
I have a couple of questions on automatic referencing of struct values
and interfaces.

Firstly, where in the spec does it explain that selectors
automatically reference values? The section on Selectors (http://
golang.org/doc/go_spec.html#Selectors) explains that selectors
automatically dereference pointers, so we can do this:

type S struct {}
func (s S) m1 {}
func (s *S) m2 {}

ap := &S{};
ap.m1(); // equivalent to (*ap).m1()

but I was surprised to find that we can also do this:

av := S{};
av.m2(); // equivalent to (&ap).m2();

This strikes me as somewhat unsafe. The author of struct S could
change m2 from taking a value reciever, which would cause a copy of av
to be passed, to taking a pointer, which would allow updates to av,
without any changes to client code.

My second question is why this automatic referencing is not allowed
for interfaces? Given the interface definition:

type IM interface {
m1();
m2();
}

we can do this:

var b IM = &av;

but not this

var b IM = av; // not allowed

The reason seems to be that automatic dereferencing is supported for
interface types but automatic referencing is not. This means that the
type *S implements IM (b will be automatically dereferenced in calls
to m1), but S does not, since b will not be automatically referenced
in calls to m2.

Is this understanding correct?

Here's the complete code: http://gopaste.org/view/4UjXi

Ian Lance Taylor

unread,
Nov 27, 2009, 8:05:25 AM11/27/09
to eadfrith, golang-nuts
eadfrith <eadf...@gmail.com> writes:

> Firstly, where in the spec does it explain that selectors
> automatically reference values? The section on Selectors (http://
> golang.org/doc/go_spec.html#Selectors) explains that selectors
> automatically dereference pointers, so we can do this:
>
> type S struct {}
> func (s S) m1 {}
> func (s *S) m2 {}
>
> ap := &S{};
> ap.m1(); // equivalent to (*ap).m1()
>
> but I was surprised to find that we can also do this:
>
> av := S{};
> av.m2(); // equivalent to (&ap).m2();

This is specifed in the section on Calls:

A method call x.m() is valid if the method set of (the type of) x
contains m and the argument list is compatible with the parameter
list of m. If x is addressable and &x's method set contains m,
x.m() is shorthand for (&x).m():

We introduced this because it is very common for a struct to provide
pointer methods and to be used with values. After some experience
with writing (&x).m(), it seemed clear that that was both common and
tedious, and so we permitted the compiler to take the address
automatically.


> This strikes me as somewhat unsafe. The author of struct S could
> change m2 from taking a value reciever, which would cause a copy of av
> to be passed, to taking a pointer, which would allow updates to av,
> without any changes to client code.

That is true, but we think that typically it is the definer of the
type which controls whether methods are read-only, not the user.


> My second question is why this automatic referencing is not allowed
> for interfaces? Given the interface definition:
>
> type IM interface {
> m1();
> m2();
> }
>
> we can do this:
>
> var b IM = &av;
>
> but not this
>
> var b IM = av; // not allowed
>
> The reason seems to be that automatic dereferencing is supported for
> interface types but automatic referencing is not. This means that the
> type *S implements IM (b will be automatically dereferenced in calls
> to m1), but S does not, since b will not be automatically referenced
> in calls to m2.
>
> Is this understanding correct?

Yes, that is correct.

It would be possible to implement "var b IM = av" to automatically
take the address of "av" when necessary to make the value fit the
methods, but that seems both more surprising and less common than
permitting a direct method call to take the address of the value being
passed to the method.

Ian
Reply all
Reply to author
Forward
0 new messages