TBH from that FAQ answer I would have come to the same conclusion as OP.

It literally says "Copying an interface value makes a copy of the thing
stored in the interface value". But it doesn't. Assigning to an interface
variable makes a copy of the value. Calling one of the methods on the
interface makes a copy (to pass as the receiver). But copying the interface
value itself doesn't.

And crucially, the difference means you are incentivized to use pointers to
interfaces - because that way, you avoid copying the interface-value. In
reality, of course, copying the interface value is harmless. And the parts
*where* the copies happen, you have no control over as a user of the
library - the initial boxing into an interface happens in the library, so
does the decision if a method has pointer- or value-receiver.

ISTM the FAQ-answer only strays from being wrong by then adding "Actual
implementations may apply optimizations to avoid copying as long as the
optimizations do not change the semantics". But I do think at that point,
the wrong impression already stuck. The FAQ answer is technically correct,
but it should be more important what people take away from it.

I don't really know how to fix it, except removing the mentions of
interfaces from that paragraph altogether. Because the most clear way to
describe what's happening is to describe the interface as "a struct
containing two pointers" and I'm generally opposed to using
implementation-details to describe how the language works (plus, that
description isn't even correct for all implementations). But maybe, by just
not mentioning interfaces specifically *here*, but still describe that
"copying a value" can mean "copying a pointer", if the value contains a
pointer, the right impression ends up sticking.

On Sun, Jun 6, 2021 at 10:27 AM Rob Pike <r...@golang.org> wrote:

> Can you explain the trap? I don't pick up that vibe, but I may be the
> author of that paragraph. Plus there is no such thing as a big interface.
> In the current implementation, all interfaces are the same size - a pair of
> words. You may still have a misapprehension.
>
> Try the first half of this article I know I wrote:
> https://blog.golang.org/laws-of-reflection.
>
> I recently translated a substantial C library into Go, and watching all
> the pointers disappear, at least syntactically (there were still slices),
> was marvelous.
>
> -rob
>
>
> On Sun, Jun 6, 2021 at 6:21 PM Joshua <joshua.oconno...@gmail.com> wrote:
>
>> Thanks all for the insights, I think a key takeaway for me is "Don't
>> worry about it unless it's a problem", but it's also good to know that it
>> (probably) isn't a problem!
>>
>> I'm glad at least the semantics are the same, and I guess I'll cross the
>> performance bridge if I ever come to it and someone tries to compile my
>> code with an alternative/older compiler.
>>
>> The FAQ [https://golang.org/doc/faq#pass_by_value] that raised this
>> question for me still seems to be technically correct, but I will say the
>> text definitely gives off a "If you're coming from C, pass big interfaces
>> as pointers" vibe:
>>
>> "Map and slice values behave like pointers: they are descriptors that
>> contain pointers to the underlying map or slice data. Copying a map or
>> slice value doesn't copy the data it points to. Copying an interface value
>> makes a copy of the thing stored in the interface value. If the interface
>> value holds a struct, copying the interface value makes a copy of the
>> struct. If the interface value holds a pointer, copying the interface value
>> makes a copy of the pointer, but again not the data it points to."
>>
>> I wouldn't be surprised if other people from C/C++ fall into this trap,
>> is there any chance the FAQ could be updated
>>
>> On Sunday, June 6, 2021 at 6:51:49 AM UTC+1 Amnon wrote:
>>
>>> I find that people coming to Go from C++ tend to use pointers everywhere
>>> so as to avoid copying of structs.
>>> Once they get a bit more experience, they tend to use fewer pointers,
>>> and are happier to pass structs around.
>>> Removing the "make everything a pointer" optimisation makes the code
>>> simpler, and often actually makes it run faster
>>> as fewer values escape the heap. Allocation tends to dominate Go
>>> runtime, so it is worth doing a bit more
>>> copying in order to get a bit less allocations.
>>>
>>> On Saturday, 5 June 2021 at 22:34:09 UTC+1 axel.wa...@googlemail.com
>>> wrote:
>>>
>>>> I would add that because the dynamic type of an interface value is not
>>>> known at compile time, a variable of interface type really can't (in
>>>> general) have a specific size.
>>>> If a function has an interface parameter, it must be possible to pass a
>>>> value of *any* size to it. So even aside from what the current
>>>> implementation does - any Go compiler must, in generalĀ¹, consider
>>>> interfaces to be pretty-much-pointers.
>>>>
>>>> "in general" because a compiler can, of course, determine that in a
>>>> certain scenario the value doesn't have to be packed and pass it as-is.
>>>> This is an optimization sometimes called "devirtualization". But in the
>>>> general case, a compiler can't prove that (e.g. the dynamic value in an
>>>> interface could be determined by a random number generator), so it will
>>>> always be an optimization and the default always has to be a form of boxing
>>>> into a constantly sized shape.
>>>>
>>>> All of this is a good indication, from first principles, that you don't
>>>> have to worry about the size of the dynamic value when passing it.
>>>>
>>>> What's more, in general you should trust the author of the package you
>>>> are using to give you a reasonable implementation of an interface. You
>>>> shouldn't worry what the dynamic type and value in an interface is, unless
>>>> you have very good reason to care. In this case, unless you notice that
>>>> your code is very slow if you don't use a pointer (that would be "a very
>>>> good reason to care"), you shouldn't optimize it. And if you notice, you
>>>> should open a bug against that package :) Though as established, you won't.
>>>>
>>>> On Sat, Jun 5, 2021 at 11:18 PM Ian Lance Taylor <ia...@golang.org>
>>>> wrote:
>>>>
>>>>> On Sat, Jun 5, 2021 at 2:15 PM Joshua <joshua.o...@gmail.com> wrote:
>>>>> >
>>>>> > My question is general, but for ease of communicating I'll use the
>>>>> specific example I ran into.
>>>>> >
>>>>> > I'm very new and for my first project I'm working with the bleve
>>>>> library [https://pkg.go.dev/github.com/blevesearch/bleve].
>>>>> >
>>>>> > One function I need, "Open", returns an interface, "Index".
>>>>> >
>>>>> > I'd like to write my own function to act on this interface, and
>>>>> given that I have no idea what the dynamic value of the interface is, my
>>>>> first instinct is to rather pass a pointer to the returned interface into
>>>>> my function.
>>>>> >
>>>>> > However, I see lots of calls of "If you're using pointers to
>>>>> interfaces a lot, you probably don't understand them".
>>>>> >
>>>>> > Well, what am I not understanding?
>>>>> > My worry is that I have no idea what dynamic type is lurking within
>>>>> the interface, if it's a pointer to a struct, then I obviously don't mind
>>>>> passing it into my function.
>>>>> >
>>>>> > However if it is in fact a humungous 1GB struct, then I really
>>>>> really don't want to be copying that around willy-nilly.
>>>>> >
>>>>> > Is there a way in general to avoid this, without looking at the
>>>>> library source code to see what the actual concrete type is?
>>>>>
>>>>> In the current implementations a value of interface type is always a
>>>>> pair of pointers.  Even if the value of interface type happens to
>>>>> refer to a 1GB struct, copying the interface value, including passing
>>>>> it to a function or returning it from a function, always just copies
>>>>> two pointers.
>>>>>
>>>>> Ian
>>>>>
>>>>> --
>>>>> 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/CAOyqgcUuv_qrrG8%3DdCQZv0%2BrKbnbW60XdOCwjp8M3EdOCxCNkw%40mail.gmail.com
>>>>> .
>>>>>
>>>> --
>> 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+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/golang-nuts/a891bbf5-9426-49b3-89c6-f185fe047b5en%40googlegroups.com
>> <https://groups.google.com/d/msgid/golang-nuts/a891bbf5-9426-49b3-89c6-f185fe047b5en%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAOXNBZSKudZatL9tjO%2BPSxKycp-4hEBwXDvO9z0bQtrCLSsk6w%40mail.gmail.com
> <https://groups.google.com/d/msgid/golang-nuts/CAOXNBZSKudZatL9tjO%2BPSxKycp-4hEBwXDvO9z0bQtrCLSsk6w%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEw9cNvHeFpVFyQDhGGuwuwgHi%2B1WXmg%3DR5--NCN%2BNvVw%40mail.gmail.com.

Reply via email to