-1

In most golang codebases I look, people are using types by reference:

type Foo struct {}
myFoo := &Foo{}

I usually take the opposite approach, passing everything as copy and only pass by reference when I want to perform something destructive on the value, which allows me to easily spot destructive functions (and which is fairly rare).

But seeing how references are commonplace, I guess it's not just a matter of taste. I get there's a cost in duplicating values, is it that much of a game changer? Or are there other reasons why references are preferred?

It would be great if someone could point me to an article or documentation about why references are preferred.

Thanks!

4
  • 2
    Possible duplicate of Pointers vs. values in parameters and return values; and Why should constructor of Go return address?, and returning value vs pointer in Go constructor. Commented Oct 21, 2016 at 11:16
  • Hi @icza, thanks for pointing those out, they did not appeared as suggestions as I typed. The first one indeed seems to address the same question, but the selected answer 1/ refer to "guidelines" and "good practice" without clearly stating the reasons why (but a lot of useful info, still!) and 2/ quite seems to recommend actually avoiding using &Type{} by default :) I guess it could be useful to clearly state the reasons in favor of this pattern here. Commented Oct 21, 2016 at 11:25
  • That's not only about speed, Olivier. Consider you constructed a bunch of Foos, and placed these values into several distinct containers (say, slices) copying them by value. This means each container now has a copy of each of the source value, and changing each of them in any of these containers will not have any effect on the others. Sometimes it's okay, sometimes it's not. In each case you should think what semantics you want to put to the values of a type you're creating and how do you intend to use values of that type. Commented Oct 21, 2016 at 12:19
  • Indeed :) In that example, does dereferencing upon variable initialization offers anything more than using append( myslice, &myItem ), though? Commented Oct 21, 2016 at 12:26

1 Answer 1

1

Go is pass by value. I try to use references like in your example as much as possible to remove the mental process of thinking about not making duplicates of objects. Go is mostly meant for networking & scaling, which makes performance a priority. Obvious downside of this is as you say, receiving methods can destroy the object that the pointer points to.

Otherwise there is no rule as to which you should use. Both are quite ok.

Also, somewhat related to the question, from the Go docs: Pointers vs. Values

Sign up to request clarification or add additional context in comments.

6 Comments

Hi Teoman, thanks for answer! I'll make a benchmark to try to measure the actual cost of duplication. Thanks for the doc, too, but I was actually wondering about docs around the &Type{} pattern :) I'll clarify the question.
Ok, here is a benchmark : gist.github.com/oelmekki/d7e93170b00278d73ccea052a2ee7ed7 That's about 500ms difference for 1B function calls. So I guess the conclusion is that it's worth using references for extremely intensive computation (like networking you mentioned), but not that much for smaller apps.
Just to be sure, I ran the benchmark again with setting an actual value in the Name field, this does not change the results.
@OlivierElMekki: dereferencing a pointer can be expensive, and a CPU can copy a lot of data in the same time. Structures smaller than a cache-line or 2 (which most are) aren't going to benefit performance wise from pointers. The logic of the program, sharing the address for mutability or copying the value, is going to dictate which to use.
@OlivierElMekki: benchmarks are hard to get right, especially microbenchmarks that need to take into account data locality, CPU specific cache behavior and branch prediction. In your example, the compiler could choose to completely remove either of those calls, and you could be timing something else entirely since you're not doing any real work. Using the current compiler and benchmarking tool, both those calls will take exactly the same amount of time, probably because they are optimized out
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.