0

I'm wondering what's the best practice on pointers. Should I define them on the struct or on its fields. I though it makes sense to define a pointer to the struct itself but here is an example I find intriguing. If all the fields are pointers why shouldn't I use a pointer to the entire struct instead to get an address for each field?

type Tag struct {
    Tag     *string       `json:"tag,omitempty"`
    SHA     *string       `json:"sha,omitempty"`
    URL     *string       `json:"url,omitempty"`
    Message *string       `json:"message,omitempty"`
    Tagger  *CommitAuthor `json:"tagger,omitempty"`
    Object  *GitObject    `json:"object,omitempty"`
}

A sample of the struct content below

{
  "tag": "v0.0.1",
  "sha": "940bd336248efae0f9ee5bc7b2d5c985887b16ac",
  "url": "https://api.github.com/repos/octocat/Hello-World/git/tags/940bd336248efae0f9ee5bc7b2d5c985887b16ac",
  "message": "initial version\n",
  "tagger": {
    "name": "Scott Chacon",
    "email": "[email protected]",
    "date": "2011-06-17T14:53:35-07:00"
  },
  "object": {
    "type": "commit",
    "sha": "c3d0be41ecbe669545ee3e94d31ed9a4bc91ee3c",
    "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/c3d0be41ecbe669545ee3e94d31ed9a4bc91ee3c"
  }
}
3
  • 1
    This is tricky--they're doing it to offer a user-friendly way to let any field or subset of fields be nil, like for constructing API calls that only affect some fields. If you need it, go for it; if you don't, take a pointer to the struct instead, because that will lead to less memory fragmentation. Commented Nov 10, 2014 at 17:42
  • How does nil makes it more user friendly? You can compare a string to "" if you want to see if there is any result or an empty field. Maybe I get this wrong. Commented Nov 10, 2014 at 17:51
  • Full answer coming, but they support update (PATCH) requests, and they want to be able to distinguish "leave the description field alone" (nil) from "set the description to blank" (""). Commented Nov 10, 2014 at 17:53

1 Answer 1

3

It is more efficient to have non-pointer fields, but in this case they have an odd reason to use pointers, discussed at the blog post "Go, REST APIs, and Pointers".

It looks like the struct you're talking about is defined here, in the go-github library. It makes every field a pointer so that it's trivial to pass nil for any subset of fields (just don't specify them). That way when you're constructing, say, a PATCH call to update something via the GitHub API, you can specify whether Description is just not relevant to your request (you're not updating the description) or whether you intend to set Description to "". The key thing is that "" and nil have different meanings in PATCH calls to their API.

If you have a similar desire to distinguish a zero string/struct/etc. from "not applicable to this object", you can also use pointers. If you don't need that, though, it's better not to make every field a pointer, because that will tend to make your memory usage patterns worse--little more RAM taken up, more cache misses, more stuff the GC needs to trace through, etc. An approach that doesn't add that layer of pointer indirection (but looks a tiny bit more verbose when writing code) is sql.NullString, which is just a struct with a bool and a string.

In GitHub's case, any performance impact of it isn't a huge deal--the time GitHub takes to respond to the Web request is going to dwarf any CPU-bound work their library does anyway.

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

3 Comments

It answers my question. Another issue "I have" with this lib is that it doesn't unmarshals the http response for me. Instead it returns a Tag pointer and the http response. Any idea if there is a good reason for that as well?
Don't know. Happened I'd seen the blog post about the pointers, but no idea about the rest of the library design.
The rationale here was that most of the time you probably only care about the actual structured data that GitHub returned (the Tag in your case). But in some cases, you may also want to inspect the raw http response. The most common example would be paginated responses, since the pagination links are in the http response headers. Most of the time when I use the library myself, I just assign the response object to "_", since I don't often need it.

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.