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
Compare with what happens when the interface contains a pointer: https://play.golang.org/p/UpZnHS0xDU1 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? 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.