-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uber Go style should clarify ordering for type declarations and methods in files with multiple types #146
Comments
I would also appreciate clarification please.
I tend to defines
I group /methods alphabetical by receiver type, then method name, which partially matches the style guide:
I dislike the idea of call order, because the order of calling methods can change and differ depending on the consumer. Alphabetical is more stable. |
Also related, the "Do not group declarations that are unrelated" good example shows
putting I would expect to see
For some reason, I expect the recommended file order is define all But, I don't currently see that stated anywhere in the style guide. |
Although https://github.com/uber-go/guide/blob/master/style.md#functional-options is somewhat a special case, the guidance there reads easily. My vote would be for guidance something like:
I would argue that enums are an exception as well so for enums, I see them as fit into the shared area near the top, but const & related type grouped together with the associated type defined first. They're more like a combination type so maybe below the shared const & shared vars, but above the shared types:
Also for interface checks, I like them near the type they are checking, like so:
... but I digress ... |
Types should come first: You can always group types in a new file so it does not get crowded. Accessing those types would be faster with good file naming. |
Just a vote for types next to method definitions: a struct and its methods are typically very tightly coupled to each other; it's much easier to understand the methods in the context of the state on the struct they manipulate. Type definitions away from methods means a lot more jumping around to understand a particular "class" (meaning here: struct with data + non trivial methods, vs just a struct with data). Fwiw, this also matches other major languages much better; Python would have everything indented under the class header, Java would have everything in curly braces, etc. That said I suspect the style guide authors already have an opinion on this, so we should probably just clarify (or alternatively, clarify that there is no recommended ordering). |
I'll clarify here before adding more detail to the guide, but at a high level, the guidance for ordering types in a given file is:
For example: // example.go
type Foo struct {
// ...
}
func NewFoo(/* ... */) Foo {
// ...
}
func NewFooWithDuration(d time.Duration) Foo {
// ...
}
func (f *Foo) ExportedFunc() {
// ...
}
func (f *Foo) AnotherExportedFunc() {
// ...
}
func (f *Foo) unexportedFunc() {
// ...
}
type Bar struct {
// ...
}
func NewBar(/* ... */) Bar {
// ...
}
func (b *Bar) ExportedFunc() {
// ...
}
func (b *Bar) AnotherExportedFunc() {
// ...
}
func (b *Bar) unexportedFunc() {
// ...
} For enum-like
type T uint8
const (
InvalidT T = iota
FooT
BarT
)
This is not recommended. Receiver methods are strongly related to the types of their receivers, and they should be grouped together following the same general exported -> unexported ordering as free functions.
This is a notable exception - we'll add clarification to the guide. Enum-like
All package-level Happy to discuss further or field any additional questions here while we update the guide! |
I'm willing to follow that style when the guidance is clarified. The example you provide is not alphabetized. I request that we add an additional guidance that wthin each of the above bullets the items should be alphabetized. In other words: The first alphabetic type, alphabetized constructors, alphabetized initializers, alphabetized exported recevermethods, alphabetized unexported recever methods, next alphabetic type, etc. "Call order" is brittle and will change over the life of the program. Alphabetic order is more stable. // example.go
type Bar struct {
// ...
}
func NewBar(/* ... */) Bar {
// ...
}
func (b *Bar) AnotherExportedFunc() {
// ...
}
func (b *Bar) ExportedFunc() {
// ...
}
func (b *Bar) ThirdExportedFunc() {
// ...
}
func (b *Bar) anotherUnexportedFunc() {
// ...
}
func (b *Bar) unexportedFunc() {
// ...
}
type Foo struct {
// ...
}
func NewFoo(/* ... */) Foo {
// ...
}
func NewFooWithDuration(d time.Duration) Foo {
// ...
}
func (f *Foo) AnotherExportedFunc() {
// ...
}
func (f *Foo) ExportedFunc() {
// ...
}
func (f *Foo) unexportedFunc() {
// ...
}
type Zot interface {
// ...
} Do we want to explicitly state to define all interfaces at the top? Or do we mix the interfaces alphabetically with the structs? |
We don't want to micromanage folks that much, so we probably won't add additional ordering guidance aside from what needs to be grouped together. You're welcome to enforce that as a style guideline within your team/own codebases, though!
Yes, this is true - we will also be removing "call order" as explicit guidance and instead encourage teams to determine their own "readable order" within a given grouping. We've found that for stable codebases, call order can often be a cheap proxy for readability, but acknowledge that this isn't universally true (and so would rather leave it up to teams to determine what ordering is the most readable for their code - whether it's alphabetical, call order, or whatever else).
We don't have official guidance for this (yet!), but in general, interfaces should be grouped and ordered the same as any other type definition: immediately preceding the types that implement them (where that makes sense), similar to how type definitions precede their constructors, et al. Ultimately, it will probably depend on context, so we'll probably only include guidance for common interface patterns. Agreed that it should be included with other ordering considerations, though. |
I (and several other Uber engineers) are a bit confused by the https://github.com/uber-go/guide/blob/master/style.md#function-grouping-and-ordering section, specifically for the case where there are multiple types in one file.
Should it be:
or:
The style guide states:
which makes me assume that "all type defs" at the top is correct, but it's not 100% clear from the example.
We should clarify this situation in the style guide (or, if the style guide has no opinion on it, state that as well).
The text was updated successfully, but these errors were encountered: