Interface pointer.

9,040 views
Skip to first unread message

Dougx

unread,
Feb 18, 2011, 1:20:15 AM2/18/11
to golan...@googlegroups.com
Reading a bit about how there's basically no reason to pass an interface pointer.

I realize this is the case when the interface holds the value of a pointer, but in the case when an interface holds a large data value, I'm wondering if it's better to pass the interface by pointer, rather than value. 

Or does the interface contain _actually_ contain a reference to the object it holds, even when it holds a value?

(Sorry, I looked at the language spec, but it's unclear to me; it says: "A variable of interface type can store a value of any type with a method set that is any superset of the interface. " --> This seems to indicate that in the case when the value held by the interface is large, you _would_ want to pass an interface by pointer).

Aside; why not just have the interface hold a pointer to an object? In my view, because this in unsafe; you have a defined set of methods to access the value behind the interface, but you can _also_ access the value directly, similar to a union in c; this seems to be a bad thing to me).

Be very pleased to have someone clear this up for me~

Cheers,
Doug.

Jessta

unread,
Feb 18, 2011, 1:40:00 AM2/18/11
to golan...@googlegroups.com, Dougx
On Fri, Feb 18, 2011 at 5:20 PM, Dougx <douglas...@gmail.com> wrote:
> Reading a bit about how there's basically no reason to pass an interface
> pointer.
> I realize this is the case when the interface holds the value of a pointer,
> but in the case when an interface holds a large data value, I'm wondering if
> it's better to pass the interface by pointer, rather than value.

Underneath there are optimisations to solve this issue.
http://research.swtch.com/2009/12/go-data-structures-interfaces.html


--
=====================
http://jessta.id.au

Dougx

unread,
Feb 18, 2011, 1:51:33 AM2/18/11
to golan...@googlegroups.com, Dougx
Ah, nice. That's very neat. :)

bflm

unread,
Feb 18, 2011, 1:55:10 AM2/18/11
to golang-nuts
On Feb 18, 7:20 am, Dougx <douglas.lin...@gmail.com> wrote:
> Reading a bit about how there's basically no reason to pass an interface
> pointer.
>
> I realize this is the case when the interface holds the value of a pointer,
> but in the case when an interface holds a large data value, I'm wondering if
> it's better to pass the interface by pointer, rather than value.

No, no and one more time no.

> Or does the interface contain _actually_ contain a reference to the object
> it holds, even when it holds a value?

Sometimes yes. See:
http://research.swtch.com/2009/12/go-data-structures-interfaces.html

> (Sorry, I looked at the language spec, but it's unclear to me; it says: "A
> variable of interface type can store a value of any type with a method set
> that is any superset of the interface. " --> This seems to indicate that in
> the case when the value held by the interface is large, you _would_ want to
> pass an interface by pointer).

It is clear as clear it should be. The inner workings of an interface
are an implementation detail. There's no reason to have this in the
specs (and several, why not to have in in the specs).

> Be very pleased to have someone clear this up for me~

Among other things, please read everything about Go here:
http://research.swtch.com/

BTW, the other, non Go articles there are also worth studying.

Sugu Sougoumarane

unread,
Feb 18, 2011, 3:44:00 AM2/18/11
to bflm, golang-nuts
Someone correct me if I'm wrong.
When you pass an interface by value, a copy of the original object has to be made for the receiving formal parameter. So, if your object is large, you should expect large copies to happen, just like it would happen if you passed the original object by value.

The reason why you generally want to avoid passing pointers to interfaces is because interfaces themselves can contain pointers; If your struct is large, you can make sure that you define all your methods on a pointer to the struct. That way, you can only initialize the interface with a pointer to such an object.

Having said that, there are some rare cases where it makes sense to pass pointers to interfaces. For example, gob and json can decode into a blank interface object. Useful if you don't know what to expect.

There are some interesting pitfalls: If you defined String() as a method to the pointer of a struct, then fmt.Printf() will not use it if you passed the struct by value. But it will work if you passed the pointer.

Evan Shaw

unread,
Feb 18, 2011, 4:02:32 AM2/18/11
to Sugu Sougoumarane, golang-nuts
On Fri, Feb 18, 2011 at 9:44 PM, Sugu Sougoumarane <sou...@google.com> wrote:
> Someone correct me if I'm wrong.
> When you pass an interface by value, a copy of the original object has to be
> made for the receiving formal parameter. So, if your object is large, you
> should expect large copies to happen, just like it would happen if you
> passed the original object by value.

That's not right. When you pass an interface by value, only a copy of
the interface is made. The interface is a struct consisting of just
two machine words: a pointer to type information and a pointer to
data, which is actually just used for storage if the object itself is
no larger than a machine word. (So I guess technically, if the object
is no larger than a machine word, a copy is made, but that seems
reasonable to me.)

- Evan

Jan Mercl

unread,
Feb 18, 2011, 4:05:59 AM2/18/11
to golan...@googlegroups.com, bflm
On Friday, February 18, 2011 9:44:00 AM UTC+1, Sugu Sougoumarane wrote:
Someone correct me if I'm wrong.
When you pass an interface by value, a copy of the original object has to be made for the receiving formal parameter. So, if your object is large, you should expect large copies to happen, just like it would happen if you passed the original object by value.
No. Interface, in it's gc implementation is a value type defined like like this C pseudocode:

struct iface {
    typeinfo *typ
    payload union {
        data *void
        numdata int
    }
}

When the interface contains a small enough type to be included in the payload field (e.g. int), it's right there. Otherwise the payload is a pointer to the actual data. How to interpret the payload field is determined by the value of the typeinfo ("type tag"). Thus copying an interface is always copying a two field struct regardless of the size of the contained type.

Jessta

unread,
Feb 18, 2011, 4:08:45 AM2/18/11
to Sugu Sougoumarane, bflm, golang-nuts
On Fri, Feb 18, 2011 at 7:44 PM, Sugu Sougoumarane <sou...@google.com> wrote:
> Someone correct me if I'm wrong.
> When you pass an interface by value, a copy of the original object has to be
> made for the receiving formal parameter. So, if your object is large, you
> should expect large copies to happen, just like it would happen if you
> passed the original object by value.

This copy would only happens when you actually call the methods on
the interface.

--
=====================
http://jessta.id.au

Sugu Sougoumarane

unread,
Feb 18, 2011, 3:48:25 PM2/18/11
to Jessta, bflm, golang-nuts
I see the optimization here. The language doesn't have operations that allow you to directly access the value stored by the interface. So, you can maintain value semantics without having to copy.
All you have to do is defer the copy until a type assertion. A method invocation falls in this category since there is an implied type assertion there.

Steven

unread,
Feb 18, 2011, 4:02:49 PM2/18/11
to Sugu Sougoumarane, Jessta, bflm, golang-nuts
On Fri, Feb 18, 2011 at 3:48 PM, Sugu Sougoumarane <sou...@google.com> wrote:
I see the optimization here. The language doesn't have operations that allow you to directly access the value stored by the interface. So, you can maintain value semantics without having to copy.
All you have to do is defer the copy until a type assertion. A method invocation falls in this category since there is an implied type assertion there.

Which made me think of a question I've been wondering about. Given:

type I interface { GetValue() int }

type Int int
func (i Int) GetValue() int { return int(i) } 

type T struct {
    Int
    [1000]byte
}

func main() {
    v := I(T{Int: 5})
    
    _ = v.GetValue()
}

My assumption would be that only the Int is copied, not the whole T struct. Is this correct?

Andrew Gerrand

unread,
Feb 18, 2011, 4:21:47 PM2/18/11
to Steven, Sugu Sougoumarane, Jessta, bflm, golang-nuts

No, but not in the way you think.

Calling a method with a value receiver necessitates copying that
value. If you defined your method on *Int instead of Int, it would
behave as you expect.

Andrew

Steven

unread,
Feb 18, 2011, 4:49:32 PM2/18/11
to Andrew Gerrand, Sugu Sougoumarane, Jessta, bflm, golang-nuts
I'm asking if the current Go implementation is smart enough to only copy what it needs to make the function call. I'm not sure you've answered that question. The T struct won't fit into the receiver of the function GetValue, so I can't see where it would be copied to. Unless embedded dispatch requires repeated copies (in which case, the implementation is extremely dumb, and should be rethought, but I don't think this is the case), I can't see how the method call would result in the [1000]byte being copied.

Also, I don't see how defining the method on a pointer would behave "as I expect", since in that case the only copies being made should be of pointers (and I would have to be storing a *T in the interface).

(PS - Ignore that I forgot to name the [1000]byte)

Andrew Gerrand

unread,
Feb 18, 2011, 5:11:45 PM2/18/11
to Steven, Sugu Sougoumarane, Jessta, bflm, golang-nuts
My apologies, I read your question too quickly.

On 18 February 2011 13:49, Steven <stev...@gmail.com> wrote:
> I'm asking if the current Go implementation is smart enough to only copy
> what it needs to make the function call. I'm not sure you've answered that
> question.

In this case, only the inner Int will be copied. It wouldn't make
sense to copy the outer T struct when invoking GetValue.

Your interpretation here is correct:

> The T struct won't fit into the receiver of the function GetValue,
> so I can't see where it would be copied to. Unless embedded dispatch
> requires repeated copies (in which case, the implementation is extremely
> dumb, and should be rethought, but I don't think this is the case), I can't
> see how the method call would result in the [1000]byte being copied.

Sorry for the confusion.
Andrew

Reply all
Reply to author
Forward
0 new messages