Does golang's go fmt not format brackets? - go

So I've been trying to use golang again and I remembered go has a formatting tool to clean up your source. So When I run go fmt on my project the following error gets spit out:
expected declaration, found '{'
I was expecting go fmt to fix my brackets to respect go's syntax requirements, but it just spits out an error. Is this intended functionality or is it supposed to actually put the bracket on the correct line (same line as the function declaration)?
Basic code in question that I was expecting to be properly formatted:
package main
func main()
{
println("Learning go again")
}

Go has some very strong opinions about what a valid code is.
This is one of the cases. Unlike many other C-family languages that allow putting curly bracket of function body declaration on the same line or on the next line (or even ten lines after, if you fancy), Go compiler allows it to be put only on the same line.
Another example is the else statement. Where in other languages
if {
}
else {
}
May be valid or even preferred, in Go only compiling else statement is of the form
if {
} else {
}
The go fmt will fix empty or missing spaces though:
func main() {
fmt.Println("Hello, playground")
}
func main(){
fmt.Println("Hello, playground")
}
Will both become
func main() {
fmt.Println("Hello, playground")
}

Related

How to check for type errors in errors.Errorf()?

Calls to string formatting functions like fmt.Printf seem to be a weak spot for the Go compiler. I end up with lots of bugs (using the wrong formatter after a refactor, forgetting to include all the arguments) that only reveal themselves at runtime. So I end up having to squint hard every time I write one of these.
I did some research today and discovered go tool vet, which appears to work for fmt.Printf, but it doesn't catch mistakes in errors.Errorf (see below).
import "github.com/pkg/errors"
func ReturnError(s string, i int) error {
// Swap %d and %s, and forget to include the second argument
return errors.Errorf("invalid arguments %d and %s", s)
}
Is there an analog to go tool vet that can capture string formatting errors in errors.Errorf()? Also, for my own understanding, why is this such a hard problem? It doesn't seem any more difficult for the Go compiler to catch string formatting type errors than any other kind of type errors.
You can tell go vet which functions to check for (compare godoc.org/cmd/vet):
$ cat x.go
package main
import "github.com/pkg/errors"
func ReturnError(s string, i int) error {
// Swap %d and %s, and forget to include the second argument
return errors.Errorf("invalid arguments %d and %s", s)
}
$ go vet x.go
$ go vet -printfuncs Errorf x.go
# command-line-arguments
./x.go:7: Errorf format %d has arg s of wrong type string
It's not straightforward to do this better for a number of reasons:
Format strings are run-time values: You might well call fmt.Sprintf(prefix + "%s", ...). So it is impossible to catch all invalid format strings at compile time.
Format strings don't have a special type. Hence the compiler can't easily determine that some function (errors.Errorf in this case) expects its arguments to behave like fmt.Printf just by looking at the function definition.

Is there a way to find not handled errors in go code?

Let's assume the following code:
func main() {
doStuff()
}
Sound good, until your program runs without any error but does nothing because you just forgot that doStuff() actually looks like:
func doStuff() error {
// ...
return errors.New("woops!")
}
What we should do ist:
func main() {
err := doStuff()
if err != nil {
panic(err)
}
}
Or at least (to make it obvious):
func main() {
_ = doStuff()
}
There are so many go tools out there like. Is there a simple way to check my code for not handled error return values?
As #eugecm suggested, github.com/kisielk/errcheck will do this, as will github.com/GoASTScanner/gas . Also, github.com/alecthomas/gometalinter makes it easy to download a collection of linters and run them in parallel, and includes both of the above.
So,
go get github.com/alecthomas/gometalinter
gometalinter --install
gometalinter
would download gometalinter, which will then install a number of error and style checkers and run them in parallel, reporting the results.
The relevant results from your example would be like:
main.go:13::warning: Errors unhandled.,LOW,HIGH (gas)
main.go:13::warning: error return value not checked (doStuff()) (errcheck)
I recommend gometalinter because it gives results like the above, where running errcheck on a bare command just says main.go:13:10 doStuff() (because errcheck is a program that only checks for unchecked error return values, so no additional information is really necessary).

What's the difference in Golang to run a function with or without go

I am new to Go. My question is what's the difference to run a function with or without Go. For example in a .go file I have one test() function, when I call this function what's the difference for "test()" and "go test()".
test() will run when you call it. go test() will run asynchronously on its own completely independent of test().
If you have a program like this:
func main() {
test("bob")
go test("sue")
}
func test(msg string) {
fmt.Printf("hello %v", msg)
}
You will only see output
hello bob
since the main function execution jumps right through to the end. There is nothing waiting for go test("sue") to complete since it's its own independent function.
You can block for go test("sue") by putting in a time.Sleep or a command line input with fmt.Scanln(&input)
Go playground

Why does go fmt allow empty brackets?

I was just wondering why these brackets haven't been removed after running go fmt, does their use have a function?
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
{
{
{
}
}
}
}
Example here, thanks.
They basically function like an internal namespace, so any definition(s) you put in between an encapsulating brace will not be visible outside of it.
// ... other code above ...
{
a := 5 // declare a
}
a = 5 // compiler error, a is undeclared
And plus formatting tools such as gofmt or autopep8 (for python) do not modify a given file beyond adding/removing whitespace or newline characters to already existing code.
Brackets on their own denote code Blocks. From the spec:
A block is a possibly empty sequence of declarations and statements within matching brace brackets.
These are part of the Go syntax, and go fmt formats them according the its formatting rules.

parse the fragment and find all top level definitions

The service I'm writing receive code snippets and process them, the snippets could either be complement program or a fragment, if it is a fragment, I need to add the enclosing main function. For example, the snippet:
var v int
v = 3
fmt.Println(v)
should be classified as a fragment, and add main to it:
func main() {
var v int
v = 3
fmt.Println(v)
}
If the snippet is:
package main
import "fmt"
func main() {
fmt.Println("hello")
}
then no modification should be done.
The way I'm doing now is run the go parser against the snippet:
var fset *token.FileSet
file, err := parser.ParseFile(fset, "stdin", code, 0)
if err != nil {
// add function
code = fmt.Sprintf("func main() {\n%s\n}", code)
// ...
}
This works for the 1st snippet above, however it fails if the fragment has a main function after some other declarations, e.g.
type S struct {
a int
}
func main() {
fmt.Println("foo")
}
I also try to look into the file returned by ParseFile, check the Decls, but it looks it will stop parsing after the 1st error, so Decls is nil in this case. So my question is is there a robust way to handle this?
PS. The inclusion of package clause and the required imports are not relevant because I'm feeding the processed code into golang.org/x/tools/imports anyway.
The dumbest thing that might work is after reading in the file (to a buffer most likely), is to do a string search for func main(){.
If it isn't formatted already, you might need to change that to a regex with whitespaces, but it should be pretty straight-forward.

Resources