Recently I started studying go-ethereum and this was my first time using golang. C++ is my main language and I'm a bit puzzled due to variable names in go-ethereum project.
core/state/managed_state.go:25:type account struct {
core/state/state_object.go:98:type Account struct {
There are both "account" and "Account" types in state package, which seems weird.
I've checked Naming convention for similar Golang variables, and it still looks terrible.
And what I've found is that they use a lot of "Node" struct in different packages. Definitely they do have different purposes and structures.
Are these kinds of naming is convention and popular in golang?
If you have any good references for naming convention in golang (e.g. open source projects or books), could you please name some of them? It would be really appreciated.
There are both "account" and "Account" types in state package, which seems weird.
There is a meaningful difference between these two names in the language specification.
From the Go Language Specification:
An identifier may be exported to permit access to it from another
package. An identifier is exported if both:
the first character of the identifier's name is a Unicode upper case
letter (Unicode class "Lu"); and
the identifier is declared in the
package block or it is a field name or method name.
All other identifiers are not exported.
So, taking a closer look at the go-ethereum codebase, here are my observations:
type account in managed_state.go is an internal implementation detail, providing a type for the accounts field in the exported ManageState struct
type Account in state_object.go is an exported identifier
I think the implementation choice make more sense when you look at the generated documentation.
In particular, the Account type is front and center, detailing a data structure that's of interest to consumers of the package.
When you look at the documentation for the ManageState struct, the unexported fields are purposely not documented. This is because they're internal details that don't impact the exported interface and could easily be changed without impacting users of the package.
In regards to naming recommendations, see the Names section in Effective Go.
Related
It's a random and stupid question, but I have no clue what the i stands for in structs with members like:
[starting character]i_[some specifier]
Examples are like: bio struct, everytime dm_target is referenced, bvec_iter.
Whenever I read such a variable I read the complete name in my head, and it's very frustrating to me that I can't do it with these.
There no meaning in i_, it's not special.
A loooong time ago structure members shared the same namespace as variables and such, they had to be unique - some people are used to that. And it is subjectively nice to have structure members starting with a unique prefix - IDE autocompletion works better, and it's easier to do lookup.
In the case of struct bio members, bi_ is just a shortcut for... bio_.
In the case of struct dm_target *ti variable name, ti looks like a nice shorter form of this used in C++ and Python for referencing the current object.
In the case of struct bvec_iter, bi_ is just a shorthand of bvec_iter. Above, you have struct bio_vec that uses bv_ for struct members.
These are just conventions that a specific developer used to mark some abstractions in their source code. It has no specific meaning.
It's also easier to look sometimes - when I see iter->bi_stuff, I can "suspect" that iter is a pointer to something bi related (bio? bvec_iter?). In the context of many, many variables, such small clues are nice for the eye.
This all is subjective. It is way more important to follow one convention, rather that what convention it is.
I am reading mixed opinions on how to name structs and the files that contain them. I'm also having a hard time finding detail on multi-word structs.
What is the most standard way to name my structs and the files that contain them in the following project?
I have an executable project with 2 structs:
Foo
FooBar
I want to declare the structs in their own file so I can create test files. Each will get imported into main.go.
Do I name the structs PascalCase? if not, how?
How should the go files be named?
edit:
This doc is why I went with Pascal Case first, but it is a one word struct and doesn't show it being used in a separate file. https://tour.golang.org/moretypes/2
The effective go blog post in the official Golang blog helps a lot with this.
The Package Names section and the Mixed Caps as suggested by icza are specially helpful.
I also had this discussion with the community in the official slack channel a couple months ago, and most agreed that files should be always lowercase. If the names are too big, you can use underscores , be be careful: the go build will ignore files starting with _, and don't use specific suffixes, like _test.go and OS/arch names, like _amd64.go or _linux.go. The build tool will only use those last ones in the specific OSs/architectures. This is specified the the build docs.
So if you are creating a struct called FooBar, your file can either be foobar.go or foo_bar.go.
I would like to define my Error Codes in a package models.
error.go
package models
const{
EOK = iota
EFAILED
}
How can I use them in another package without referring to them as models.EOK. I would like to use directly as EOK, since these codes would be common across all packages.
Is it the right way to do it? Any better alternatives?
To answer you core question
You can use the dot import syntax to import the exported symbols from another package directly into your package's namespace (godoc):
import . "models"
This way you could directly refer to the EOK constant without prefixing it with models.
However I'd strongly advice against doing so, as it generates rather unreadable code. see below
General/style advice
Don't use unprefixed export path like models. This is considered bad style as it will easily globber. Even for small projects, that are used only internally, use something like myname/models. see goblog
Regarding your question about error generation, there are functions for generating error values, e.g. errors.New (godoc) and fmt.Errorf (godoc).
For a general introduction on go and error handling see goblog
W.r.t. the initial question, use a compact package name, for example err.
Choosing an approach to propagating errors, and generating error messages depends on the scale and complexity of the application. The error style you show, using an int, and then a function to decode it, is quite C-ish.
That style was partly caused by:
the lack of multiple value returns (unlike Go),
the need to use a simple type (to be easily propagated), and
that gets translated to text with a function (unlike Go's error interface), so that the local language strings can be changed.
For small apps with simple errors strings. I put the packages' error strings at the head of a package file, and just return them, maybe using errors.New(...), or fmt.Errorf if the string needs to be completed using some data.
That 'int' style of error reporting doesn't offer something as flexible as Go's error interface. The error interface lets us build information-rich error structures, to return useful information, and not just an int value or string.
An implication is different packages can yield different real-types which implement the Error interface. We don't need to agree a single error real-type across an entire set of packages. So error is an interface which can be easily propagated, like an int, yet, the real-type of error can be much richer than an int. Error generation (implementing Error) can be as centralised or distributed as we need, unlike strerror()-style functions which can be awkward to extend.
The Effective go has following advice on naming of getters:
Go doesn't provide automatic support for getters and setters. There's
nothing wrong with providing getters and setters yourself, and it's
often appropriate to do so, but it's neither idiomatic nor necessary
to put Get into the getter's name. If you have a field called owner
(lower case, unexported), the getter method should be called Owner
(upper case, exported), not GetOwner. The use of upper-case names for
export provides the hook to discriminate the field from the method. A
setter function, if needed, will likely be called SetOwner. Both names
read well in practice:
Source: https://golang.org/doc/effective_go.html#Getters
Now, this advice doesn't seem to consistent as the stdlib itself violates this multiple times.
As you can see in above screenshot, there are multiple methods which use GetX naming convention which is advised against in the effective go guide.
So the question is is the advice given in guide wrong or these methods are named wrongly & would be fixed in future versions?
These names are not consistent with Go naming by design. Rob Pike, one of the Go creators, says this about the names in the OS package:
There are inconsistencies but this is the key point. It should be Stdout not StdOut, because that name is coming from the underlying system. Similarly it's Fprintf not FPrintf or FPrintF because that is a very familiar name. These names are coming into Go, not being created there, and the initial cap is the admission fee.
The names will not be changed in a future version of Go.
[go-nuts] FunctionName caseinconsistencies
A lot of the all lowercase names were chosen before we had really
figured out what the naming conventions should be. The rule we
adopted, which might be worth revisiting later, was that entry points
in package os or syscall, which are named after equivalents in C, just
had a single capital at the beginning, to avoid needing to decide
where the internal capitalizations are in abbreviations like geteuid
or getwd or chdir. Names like Readdirnames, which are actual words,
might be worth revisiting at some point.
Russ
os: inconsistent casing in names #1187
Is there any sort of rule about the casing of functions used in the
"os" package? Looking through, it doesn't sound like it's very easy
to recall whether a given function should be called LikeThat or
Likethat.
For instance:
Mkdir
MkdirAll
TempDir
Getenv
ForkExec
Readlink
ReadAt
Readdir
It feels very ad-hoc, and hard to recall.
It's a known issue. It's unplanned.
The term "getters" refers to methods on structs that allow you to read values of (often unexported) fields on that struct. The functions you're pointing to are top-level functions which allow you to read values from the OS. That idiomatic rule is not relevant to this case.
Perhaps this is a silly question, but is there a way to find all functions (in the standard library or GOPATH) that return a specific type?
For example there are many functions that take io.Writer as an argument. Now I want to know how to create an io.Writer and there are many ways to do so. But how can I find all the ways easily without guessing at packages and looking through all the methods to find those that return an io.Writer (or whatever other type I'm after)?
Edit: I should extend my question to also find types that implement a specific interface. Sticking with the io.Writer example (which admittedly was a bad example for the original question) it would be good to have a way to find any types that implement the Writer interface, since those types would be valid arguments for a function that takes takes an io.Writer and thus answer the original question when the type is an interface.
Maybe not the best way but take a look at the search field at the top of the official golang.org website. If you search for "Writer":
http://golang.org/search?q=Writer
You get many results, grouped by categories like
Types
Package-level declarations
Local declarations and uses
and Textual occurrences
Also note that io.Writer is an interface, and we all know how Go handles interfaces: when implementing an interface, there is no declaration of intent, a type implicitly implements an interface if the methods defined by the interface are declared. This means that you won't be able to find many examples where an io.Writer is created and returned because a type might be named entirely different and still be an io.Writer.
Things get a little easier if you look for a non-interface type for example bytes.Buffer.
Also in the documentation of the declaring package of the type the Index section groups functions and methods of the package by type so you will find functions and methods of the same package that return the type you're looking for right under its entry/link in the Index section.
Also note that you can check the dependencies of packages at godoc.org. For example you can see what packages import the io package which may be a good starting point to look for further examples (this would be exhausting in case of package io because it is so general that at the moment 23410 packages import it).
In my days coding I'm personally rare in need to find functions returning Int16 and error(func can return few values in Go, you know)
For second part of your question there exists wonderful cmd implements written by Dominik Honnef go get honnef.co/go/implements
After discover type that satisfy your conditions you can assume constructor for type (something like func NewTheType() TheType) would be just after TheType declaration in source code and docs. It's a proven Go practice.