My question is whether or not a copy of a value is made when a method is invoked where _ is the receiver.
type Foo struct {
// Many fields, making a large struct
}
func (_ Foo) Test(v *T) int {
// Here we can't use the receiver but the method is still needed
}
So I'm wondering if Go implementations will still copy the Foo value when Test() is invoked, even though it's impossible to actually mutate the receiver value.
var f Foo
f.Test() // Is this making a copy?
I would also wonder about the case of a pointer, which is automatically dereferenced by default.
var f = new(Foo)
f.Test() // Is this making a copy?
I tried looking at the assembly, and I think it may be making the copy, but I just don't know enough to be sure.
For details on the situation:
This is an odd case where I can't use a pointer. The code is machine generated and required to cause a type to fulfill an interface while doing some initialization on the v parameter. (The generated code has metadata about the Foo that gets set on v.)
So if I make the receiver a pointer, the interface won't be fulfilled for "value" instances. This method will be invoked once for each instance, and instances can sometimes be large and/or created in great numbers, which is why I would like to avoid an unnecessary copy.
According to this blog post, the caller allocates stack elements for return values and the callee populates them.
This leads me to believe that the value is copied and then discarded.
That or a specialized callee would have to be generated in the case of _ receiver
Related
Zap initializes its default option struct as follows in its grpc interceptor:
var (
defaultOptions = &options{
levelFunc: DefaultCodeToLevel,
shouldLog: grpc_logging.DefaultDeciderMethod,
codeFunc: grpc_logging.DefaultErrorToCode,
durationFunc: DefaultDurationToField,
messageFunc: DefaultMessageProducer,
timestampFormat: time.RFC3339,
}
)
And the later zap performs a copy of values:
*optCopy = *defaultOptions
What is the purpose of declaring the variable defaultOptions as a pointer and then later dereferencing it for copying? I was wondering if there is any issue with not using pointer:
defaultOptions = options{
levelFunc: DefaultCodeToLevel,
shouldLog: grpc_logging.DefaultDeciderMethod,
codeFunc: grpc_logging.DefaultErrorToCode,
durationFunc: DefaultDurationToField,
messageFunc: DefaultMessageProducer,
timestampFormat: time.RFC3339,
}
optCopy = &options{}
*optCopy = defaultOptions
A possible advantage with using a pointer is that you can then have that pointer set to nil; obviously if it is nil, you can't dereference it; but this might be used to indicate that there are no options and there may be code to handle this.
Caveat: I am not a Go programmer.
My guess, based on previous issues I had with big systems, is that with configuration structs, if for any reason some part of your software changes the value of something, that change will propagate to any function/member who has that pointer, and most of the times you don't want that to happen, you usually want that the configuration that you probably read from a file, stays the same, even if some function needs to do a transformation of a specific field of the struct holding that configuration.
So basically, you keep the original struct fresh, but you can send the pointer around to have its contents copied anywhere.
That's my educated guess, it is most likely an application architecture decision.
Edit: After further pondering:
If the author of the code had in his mind the idea of moving that data structure everywhere in his code, in multiple levels deep and broad, declaring it as value would mean he would have to copy it every time he wanted to move the data from function to function, or that the data structure could be erased by the end of execution of scope, whereas with a pointer he can move only the pointer around (much faster) and then only copy the data once the pointer arrives at the destination function.
I have the following code. https://play.golang.org/p/YAa6cgtA3Vo
The address of the receiver pointer varies between method calls. This is perplexing. Can anyone explain why this is the case? Do I need to pass a pointer to a receiver as an argument in order to maintain the same address?
type myStruct struct {
//struct content is irrelevant
}
func (ptrToStruct *myStruct) returnAddress() **myStruct {
return &ptrToStruct
}
func (ptrToStruct *myStruct) method1() {
addressOfPtr := ptrToStruct.returnAddress()
fmt.Println(&ptrToStruct)
fmt.Println(addressOfPtr)
if &ptrToStruct != addressOfPtr {
fmt.Println("Different addresses!")
}
}
EDIT:
What I want is the address of ptrToStruct and not its value. I know that I could just get it in method1() by typing addressOfPtr = &ptrToStruct but in my use case I have some logic happening in the returnAddress() method and I need it to come from there.
That's simple: when you have var ms myStruct somewhere,
calling ms.returnAddress() would pass the address of the ms variable to returnAddress, and that address would always be the same (this is easily verifyable — try it itself).
Now consider that the ptrToStruct in the returnAddress definition is just a special argument to be passed to that method, and it has a concrete type — *myStruct.
This type internally is just an integer — large enough to store an address of any memory location on your platform/OS combination.
Now consider that when the call ms.returnAddress() is performed, the address of the ms variable is taken and written to the ptrToStruct argument passed to returnAddress. And that argument is also a variable — with the lifetime equal to the duration of the function call, and visible only in that function's body.
This variable is automatically created on the call stack by the code which prepares the function call.
(And the same happens to all the other method arguments.)
So, when you take the address of ptrToStuct, you take the address of a variable appeared at some location on the call stack which will be gone once the method returns.
Now consider that:
goroutine stacks in Go are growable (and hence may be relocated in memory when grown);
a method may be called from different goroutines (each has its own stack);
even if the method is called from the same goroutine multiple times, it may be called from different places in the code path executed by that goroutine.
All of the above may lead to the address of ptrToStruct variable being essentially random from call to call.
What you (probably) actually want is just returning the value of ptrToStruct as is, not its address.
If you feel like not really getting into how ptrToStruct springs into existence and vanishes, consider starting with this.
Consider a binary tree node:
type Node struct {
value uint8
left, right *Node
}
If I want to add a function to each Node, should it be:
A: func (n *Node) height() int
or
B: func (n Node) height() int
I want to know which of A or B you would choose and why.
I can model linked lists or recursive structs, but I don't know when the receiver should be a pointer or not-a-pointer.
The main difference is the idea of pass by value vs pass by reference
When you're using example A you're passing be reference, meaning that any changes you apply to n inside of func (n *Node) height will apply to the Node you're using to call Node.height().
By comparison, what you're doing in example B is passing by value where you're really just passing a copy of the Node you're using to call Node.height() so any changes to that Node will not apply outside of the function.
Here is a small playground to demonstrate the differences: http://play.golang.org/p/JodPRPBHDg
Notice in the example that when you call node.incHeight(), it goes to the function:
func (n Node) incHeight() uint8 {
n.value++
return n.value
}
Because this is pass by value the node.value is still the same unless you store the returned value as node.value. However, if you call node.incrementHeight() it goes to the function:
func (n *Node) incrementHeight() {
n.value++
return
}
This will change the value of node.value without needing to return anything because its referencing the original struct, rather than a copy of the struct.
So in answer to which would you choose and why, it really depends on whether you want to be able to make lasting changes to the struct you're using to call the function or if you'd rather just pass a copy that can see and alter the values but only while within the function and not have any lasting effects on the original struct.
There is a very nice explanation in https://code.google.com/p/go-wiki/wiki/Style
Receiver Type
Choosing whether to use a value or pointer receiver on
methods can be difficult, especially to new Go programmers. If in
doubt, use a pointer, but there are times when a value receiver makes
sense, usually for reasons of efficiency, such as for small unchanging
structs or values of basic type. Some rules of thumb:
If the receiver is a map, func or chan, don't use a pointer to it.
If the receiver is a slice and the method doesn't reslice or reallocate the slice, don't use a pointer to it.
If the method needs to mutate the receiver, the receiver must be a pointer.
If the receiver is a struct that contains a sync.Mutex or similar synchronizing field, the receiver must be a pointer to avoid copying.
If the receiver is a large struct or array, a pointer receiver is more efficient. How large is large? Assume it's equivalent to passing
all its elements as arguments to the method. If that feels too large,
it's also too large for the receiver.
Can function or methods, either concurrently or when called from this method, be mutating the receiver? A value type creates a copy
of the receiver when the method is invoked, so outside updates will
not be applied to this receiver. If changes must be visible in the
original receiver, the receiver must be a pointer.
If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer
receiver, as it will make the intention more clear to the reader.
If the receiver is a small array or struct that is naturally a value type (for instance, something like the time.Time type), with
no mutable fields and no pointers, or is just a simple basic type
such as int or string, a value receiver makes sense. A value
receiver can reduce the amount of garbage that can be generated; if
a value is passed to a value method, an on-stack copy can be used
instead of allocating on the heap. (The compiler tries to be smart
about avoiding this allocation, but it can't always succeed.) Don't
choose a value receiver type for this reason without profiling
first.
Finally, when in doubt, use a pointer receiver.
Seems like you'd ALWAYS want this:
func (self *Widget) Do() {
}
instead of this
func (self Widget) Do() {
}
If so, then the way to get the former semantics OUGHT to be by using the latter syntax. i.e. receivers ought to be pass by reference.
It is because everything in Go is pass by value. This makes it consistent with other C family languages, and means that you never need to remember whether the situation you're looking at is pass by value or not.
From that link:
As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See the next section for a discussion of how this affects method receivers.)
Then later:
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
For programmers unaccustomed to pointers, the distinction between these two examples can be confusing, but the situation is actually very simple. When defining a method on a type, the receiver (s in the above examples) behaves exactly as if it were an argument to the method. Whether to define the receiver as a value or as a pointer is the same question, then, as whether a function argument should be a value or a pointer. There are several considerations.
First, and most important, does the method need to modify the receiver? If it does, the receiver must be a pointer. (Slices and maps act as references, so their story is a little more subtle, but for instance to change the length of a slice in a method the receiver must still be a pointer.) In the examples above, if pointerMethod modifies the fields of s, the caller will see those changes, but valueMethod is called with a copy of the caller's argument (that's the definition of passing a value), so changes it makes will be invisible to the caller.
By the way, pointer receivers are identical to the situation in Java, although in Java the pointers are hidden under the covers; it's Go's value receivers that are unusual.
Second is the consideration of efficiency. If the receiver is large, a big struct for instance, it will be much cheaper to use a pointer receiver.
Next is consistency. If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used. See the section on method sets for details.
For types such as basic types, slices, and small structs, a value receiver is very cheap so unless the semantics of the method requires a pointer, a value receiver is efficient and clear.
Sometimes you don't want to pass by reference though. The semantics of
func (self Widget) Get() Value {
}
Can be useful if for instance you have a small immutable object. The caller can know for certain that this method doesn't modify it's reciever. They can't know this if the reciever is a pointer without reading the code first.
To expand on that for instance
// accessor for things Config
func (self Thing) GetConfig() *Config {
}
Just by looking at this method I can know GetConfig is always going to return the same Config. I can modify that config but I can't modify the pointer to Config inside Thing. It's pretty close to a const pointer inside of Thing.
Seems like you'd ALWAYS want this:
No. The value receiver is more general. It can be used in all the places that a pointer receiver can; but a pointer receiver cannot be used in all the places that a value receiver can -- for example, if you have an rvalue expression of the type Widget; you can call value-receiver methods on it, but not pointer-receiver methods.
Having defined
type MyInt int
I would like to define a method .ShowMe() that just prints the value. I can define this either using *MyInt:
func (this *MyInt) ShowMe() {
fmt.Print(*this, "\n")
}
Or using MyInt:
func (this MyInt) ShowMe() {
fmt.Print(this, "\n")
}
In what cases is it recommended to define methods on values, instead of on pointers?
There are two questions to ask yourself when making this decision:
Do I want to be able to modify the receiver's value?
Will copying the receiver's value be expensive?
If the answer to either of these questions is yes, then define the method on a pointer.
In your example, you don't need to modify the receiver's value and copying the receiver isn't expensive.
For deciding the answer to #2, my rule of thumb is: if the receiver is a struct with more than one field, pass by pointer. Otherwise pass by value.
The Go FAQ (CC-licensed) has an answer:
Should I define methods on values or pointers?
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
For programmers unaccustomed to pointers, the distinction between
these two examples can be confusing, but the situation is actually
very simple. When defining a method on a type, the receiver (s in the
above example) behaves exactly as if it were an argument to the
method. Whether to define the receiver as a value or as a pointer is
the same question, then, as whether a function argument should be a
value or a pointer. There are several considerations.
First, and most important, does the method need to modify the
receiver? If it does, the receiver must be a pointer. (Slices and
maps are reference types, so their story is a little more subtle, but
for instance to change the length of a slice in a method the receiver
must still be a pointer.) In the examples above, if pointerMethod
modifies the fields of s, the caller will see those changes, but
valueMethod is called with a copy of the caller's argument (that's
the definition of passing a value), so changes it makes will be
invisible to the caller.
By the way, pointer receivers are identical to the situation in Java,
although in Java the pointers are hidden under the covers; it's Go's
value receivers that are unusual.
Second is the consideration of efficiency. If the receiver is large, a
big struct for instance, it will be much cheaper to use a pointer
receiver.
Next is consistency. If some of the methods of the type must have
pointer receivers, the rest should too, so the method set is
consistent regardless of how the type is used. See the section on
method sets
for details.
For types such as basic types, slices, and small structs, a value
receiver is very cheap so unless the semantics of the method requires
a pointer, a value receiver is efficient and clear.