On Sun, Jun 6, 2021 at 12:17 PM Brian Candler <b.cand...@pobox.com> wrote:

> When you assign a regular (non-pointer) value to an interface variable, it
> does take a copy of that value:
> https://play.golang.org/p/XyBREDL4BGw
>

Yupp, as I said :)


> As to whether the value is copied when you copy a non-pointer interface
> value to another interface variable, I'm having a hard time finding any way
> to demonstrate it one way or the other.  If you write a mutator method then
> it needs to take a pointer (which a non-pointer value doesn't satisfy).
> And I can't find a simple way to get a pointer to the struct itself or its
> member, when it's held inside an interface value.  Maybe it's possible via
> reflect?
>

If you know about the implementation, you can use unsafe:
https://play.golang.org/p/IgDqfJ-DaDF
Given that the contained pointer doesn't change, no copy is happening. But
of course, that assumes an implementation-view and the FAQ does point out
that a copy doesn't *have* to happen.

Purely from a language perspective, there is no way to tell. Because,
again, the FAQ entry is not *wrong*. Semantically, any implementation must
behave *as if* a copy happens.

But in any case, I think the summary is:
> * it's fine (and often a good idea) for an interface to contain a pointer
> value
> * it's almost always wrong to take a pointer to an interface
>
> On Sunday, 6 June 2021 at 10:54:03 UTC+1 axel.wa...@googlemail.com wrote:
>
>> 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.o...@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...@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...@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/3e3f8b10-3806-4959-9f44-8fe484f67a24n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/3e3f8b10-3806-4959-9f44-8fe484f67a24n%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/CAEkBMfHLsngEc%2BwdHam2b55Qt_EoOQxY-ip5SHpFG-WLFoGaBw%40mail.gmail.com.

Reply via email to