guide icon indicating copy to clipboard operation
guide copied to clipboard

Proposal: Export fields and methods of unexported types

Open abhinav opened this issue 4 years ago • 0 comments

This one will require some careful phrasing but the gist of the proposal is:

For unexported types, it's beneficial to export fields or methods to mark them as part of their "public" API is for use by other unexported types.

As a contrived example,

// counter.go
type countingWriter struct {
    writer io.Writer
    count  int
}

func (cw *countingWriter) Write(b []byte) (int, error) {
    n, err := cw.writer.Write(b)
    cw.inc(n)
    return n, err
}

func (cw *countingWriter) inc(n int) {
    cw.count += n
}

// another.go
func foo(w io.Writer) error {
    cw := &countingWriter{writer: w}
    writeABunch(&cw)
    fmt.Println("wrote", cw.count, "bytes")
}

It would be useful for the author of countingWriter to indicate which fields they intended to be accessed directly, and which are "private". The example above could be:

type countingWriter struct {
    Writer io.Writer
    Count int
}

func (*countingWriter) inc(int)

This indicates that int is for private use but the Writer and Count fields may be accessed freely. If the author wanted to protect writes to Count, maybe they'd switch to:

type countingWriter struct {
    Writer io.Writer

    count int
}

func (*countingWriter) Count() int

Obviously, there's no enforcement and this only works as a general guidance to indicate "publicness" of a field/method of a private type, but as a reader/consumer of a private type in a large package, one might find value in knowing what they should or should not touch.

abhinav avatar Mar 11 '21 19:03 abhinav