Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go Getter Methods vs Fields, Proper Naming

In Effective Go, it's clearly stated that in the case where a field is unexported (begins with a lower case letter) a getter method should have the same field name but starting with upper case; the example they give is a owner as a field and Owner as a method. And they explicitly advise against using Get in front of the getter method name.

I frequently encounter situations where I need the field to be exported for JSON marshaling, use with an ORM, or other reflection related purposes (IIRC reflect can read but not modify unexported fields), so my field would need to be called Owner in the example above and thus cannot have an Owner method.

Is there an idiomatic way of naming which addresses this situation?

EDIT: Here's a concrete example of what I'm running into:

type User struct {
    Username string `db:"username" json:"username"`
    // ...
}

// code in this package needs to do json.Unmarshal(b, &user), etc.

.

// BUT, I want code in other packages to isolate themselves from
// the specifics of the User struct - they don't know how it's
// implemented, only that it has a Username field.  i.e.
package somethingelse

type User interface {
    Username() string
}

// the rest of the code in this other package works against the
// interface and is not aware of the struct directly - by design,
// because it's important that it can be changed out without
// affecting this code
like image 913
Brad Peabody Avatar asked Jul 19 '17 11:07

Brad Peabody


People also ask

What should I name my getters and setters?

For each instance variable, a getter method returns its value while a setter method sets or updates its value. Given this, getters and setters are also known as accessors and mutators, respectively.

How do you name a getter function?

The getter should start with 'get', followed by the member name, with its first letter capitalized. Also the latest conventions I heard of, say that we should avoid multiple capital letters one after another. For example getHTMLtooltip is wrong. it should be getHtmlTooltip instead.

What's the advantage of using getters and setters that only get and set instead of simply using public fields for those variables?

The getter and setter method gives you centralized control of how a certain field is initialized and provided to the client, which makes it much easier to verify and debug. To see which thread is accessing and what values are going out, you can easily place breakpoints or a print statement.

Should getter methods be public or private?

In general, they should be public. If they are private they can only be called from within your class and, since you already have access to the private variables within your class, are redundant. The point of them is to allow access to these variables to other, outside, objects. Save this answer.


2 Answers

Don't use getters and setters if your fields are exported. This just confuses the interface.

If you need a getter or setter because it does something (validation, formatting, etc), or because you need the struct to satisfy an interface, then don't export the underlying field!

If you need an exported field for the sake of JSON, database access, etc, and you need a getter/setter, then use two structs, one exported and one private, and define a custom JSON marshaler (or db access method) on the public one:

type jsonFoo struct {
    Owner string `json:"owner"`
}

type Foo struct {
    owner string
}

func (f *Foo) SetOwner(username string) {
    // validate/format username
    f.owner = username
}

func (f *Foo) Owner() string {
    return f.owner
}

func (f *Foo) MarshalJSON() ([]byte, error) {
    return json.Marshal(jsonFoo{
        Owner: f.owner,
    })
}
like image 163
Flimzy Avatar answered Oct 19 '22 18:10

Flimzy


I'm going to post this as an answer, derived after considering @Flimzy's answer, which makes a lot of sense.

The basic idea is to have one struct with exported fields which can be used for marshaling, and another separate struct which has the sole purpose of providing the methods which meet the needed interface.

This requires no custom marshaling code, and gives a clear meaning to each struct, IMO:

type user struct {
    Username string `json:"username"`
}

type ExportedUser struct {
    // EDIT: explicitly doing "user *user" instead of just doing "*user"
    // helps avoid confusion between between field names and methods
    user *user
}

func (u ExportedUser) Username() string { return u.user.Username }

func main() {
    fmt.Printf("Test: %q", ExportedUser{user: &user{Username: "joe"}}.Username())
}

The question of whether it should be user or User above is a bit unclear to me - since it may make sense for the type to be visible for use in a Go template, e.g. {{euser.User.SomeOtherField}} Thus allowing all of the fields to be accessible if needed. Regardless, the answer above functions the same either way.

like image 28
Brad Peabody Avatar answered Oct 19 '22 17:10

Brad Peabody