33

When building a simple object in go, what's the difference between these alternatives?

func NewGender(value string) Gender {
    return Gender{strings.TrimSpace(value)}
}

func NewGender(value string) *Gender {
    return &Gender{strings.TrimSpace(value)}
}
4
  • If you pass the *Gender to some other code, it can change it. Not so with the Gender. Commented Aug 25, 2015 at 16:05
  • 3
    Related/duplicate of: Why should constructor of Go return address? Commented Aug 25, 2015 at 16:21
  • the question is not exactly the same and I think @Ainar-G answer is better than the accepted for that tentative duplicate Commented Aug 29, 2015 at 18:51
  • link to where I had explained it stackoverflow.com/a/60840366/8952645 Commented Mar 24, 2020 at 23:05

4 Answers 4

25

The question is a really broad one, and it depends heavily on the rest of your API. So here are just some things you might need to consider when choosing one over another (in no particular order):

  • Unnecessary pointers lead to more work for the GC. You might win some time by returning a pointer (one word) rather than a struct (zero to many words), but some of that time might later be consumed by the GC scan.

  • Pointers can also signal presence or absence of a thing, although it's generally better to use comma-ok idiom for that, or return an error.

  • Speaking of errors, if you return nil with an error, the chance that the error will be ignored is smaller (because nil pointer dereference will result in panic). Then again, I don't think people who ignore errors are something you should really take into account.

  • If you need some form of tracking (for example, a possibility to inspect all instances ever created by your constructor), you have to return a pointer, so that all changes to the value would be visible to the inspector.

  • If most of the type's methods have a pointer receiver, or most functions in the API accept pointers to the type rather than values, it's more ergonomic to return a pointer.

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

Comments

4

The first item returned is a value, the second is a pointer. The pointer works much like a pointer in C or C++ only the value it points to is garbage collected like in C# or Java. Go offers something of a compromise between those two paradigms. The pointer is explicit and exposed, however it's still garbage collected. Here are a few somewhat obvious differences;

1) If you pass the value to a method or it is the receiver (which is often confusing) you will not be able to modify it's value, it will be a 'pass by value' like in the other languages where you are modifying a copy. Yes, even the method func (g Gender) ChangeGender() will not change the gender of the object you call it on. https://play.golang.org/

2) You can only call methods defined for the type. For example if you have g *Gender and you want to call the ChangeGender method above you will not be able to without dereferencing your pointer, just like in C/C++. The opposite is true going in the opposite direction.

3) The alternative to passing by value is by reference, you probably know how that works but in case you don't I'll explain. If you have a method func (g *Gender) ModifyGender() and an instance g := &Gender{} then when calling ModifyGender a pointer of the OS' word size will get pushed onto the stack as an argument rather than the value itself and the method will use that address to modify the memory there, persisting changes when control returns to the caller. This can vastly improve performance if you have method which work on objects that have a large memory foot print.

I'm not going to speak to performance. That should give you enough information to consider how it works in your application.

Comments

3

Just as @evanmcdonnal said the choise is more related to how you are going to use the struct.

  • If your struct is informative only and you are not planning to mutate it later, keep it simple and return a value (e.g. a Custom Error struct), in case your struct is really large but you do not plan to mutate it use a pointer (e.g. a RGB matrix)

  • If you plan to mutate your struct durign your program workflow use a pointer.

Comments

0

One thing that just bit me recently, which makes me lean toward returning pointers:

func (g *Gender) HandlePost(w http.ResponseWriter, req *http.Request) {
  fmt.Fprint(w, g.value)
}

func NewGender(value string) MyGender {
  gender := Gender{strings.TrimSpace(value)}
  http.Handle("/", http.HandlerFunc(gender.HandlePost))
  return gender
}

gen := NewGender("male")
gen.value = "female"
// http POST will still return "male"

If the constructor stores a pointer to the struct somewhere, like this one does by passing it to http.HandlerFunc, that will be a pointer to the original struct. But any code that uses the return value will be using a different copy of the struct. So changes to one won't affect the other.

Comments

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.