Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does assigning value to interface copy anything?

Tags:

go

I've been trying to wrap my head around the concept of interfaces in Go. Reading this and this helped a lot.

The only thing that makes me uncomfortable is the syntax. Have a look at the example below:

package main

import "fmt"

type Interface interface {
    String() string
}

type Implementation int

func (v Implementation) String() string {
    return fmt.Sprintf("Hello %d", v)
}

func main() {
    var i Interface
    impl := Implementation(42)
    i = impl
    fmt.Println(i.String())
}

My issue is with i = impl. Based on the fact that an interface instance actually holds a pointer reference to the actual data, it would feel more natural for me to do i = &impl. Usually assignment of non-pointer when not using & will make a full memory copy of the data, but when assigning to interfaces this seem to side-step this and instead simply (behind the scenes) assign the pointer to the interface value. Am I right? That is, the data for the int(42) will not be copied in memory?

like image 201
Ztyx Avatar asked Jan 02 '14 00:01

Ztyx


1 Answers

The data for int(42) will be copied. Try this code:

func main() {
    var i Interface
    impl := Implementation(42)
    i = impl
    fmt.Println(i.String())
    impl = Implementation(91)
    fmt.Println(i.String())
}

(Playground link)

You'll find that the second i.String() still shows 42. Perhaps one of the trickier aspects of Go is that method receivers can be pointers as well.

func (v *Implementation) String() string {
    return fmt.Sprintf("Hello %d", *v)
}

// ...
i = &impl

Is what you want if you want the interface to hold a pointer to the original value of impl. "Under the hood" an interface is a struct that either holds a pointer to some data, or the data itself (and some type metadata that we can ignore for our purposes). The data itself is stored if its size is less than or equal to one machine word -- whether it be a pointer, struct, or other value.

Otherwise it will be a pointer to some data, but here's the tricky part: if the type implementing the interface is a struct the pointer will be to a copy of the struct, not the struct assigned to the interface variable itself. Or at least semantically the user can think of it as such, optimizations may allow the value to not be copied until the two diverge (e.g. until you call String or reassign impl).

In short: assigning to an interface can semantically be thought of as a copy of the data that implements the interface. If this is a pointer to a type, it copies the pointer, if it's a big struct, it copies the big struct. The particulars of interfaces using pointers under the hood are for reasons of garbage collection and making sure the stack expands by predictable amounts. As far as the developer is concerned, they should be thought of as semantic copies of the specific instance of the implementing type assigned.

like image 141
Linear Avatar answered Sep 23 '22 12:09

Linear