mygo is an experimental toy Go preprocessor/transpiler that introduces the ? operator for more concise error handling. It aims to reduce boilerplate code by replacing verbose error checks with a single character.
For example, mygo transforms this:
s := hello()?Into this:
s, err := hello()
if err != nil {
return err
}$ go install github.com/aisk/mygo@latestCreate a file named hello.mygo with the following content:
package main
import (
"io"
"os"
)
func hello() error {
f := os.Open("hello.mygo")?
defer f.Close()
s := io.ReadAll(f)?
println(string(s))
return nil
}
func main() {
hello()
}mygo supports multiple ways to specify transpile targets:
# Transpile from stdin
$ cat hello.mygo | mygo > hello.go
# Transpile specific files
$ mygo hello.mygo
# Transpile all .mygo files in a directory (non-recursive)
$ mygo .
# Transpile all .mygo files recursively
$ mygo ./...
# Transpile all .mygo files in current directory recursively
$ mygo ...The transpiled hello.go will contain:
package main
import (
"io"
"os"
)
func hello() error {
f, err := os.Open("hello.mygo")
if err != nil {
return err
}
defer f.Close()
s, err := io.ReadAll(f)
if err != nil {
return err
}
println(string(s))
return nil
}
func main() {
hello()
}The goal of this project is to design a Go language extension with more syntactic sugar, implemented as a preprocessor. The precompiled result is completely standard Go code, indistinguishable from hand-written Go code.
Core Design Philosophy: Zero Lock-in
- If you decide this project isn't suitable, you can simply delete all
.mygofiles and continue development with the original Go code - If your team doesn't want to introduce mygo, you can edit
.mygofiles locally and commit the generated standard Go code to your version control server - The precompiled Go code has no runtime dependencies or special libraries
Design Constraints
To achieve zero lock-in, there are some intentional limitations:
- The ? operator does not support method chaining - For example,
a()?.b()?is not supported because it would require introducing intermediate variables, and it's difficult to provide reasonable names for these variables - Currently does not support the ? operator in for loop initialization statements - For example,
for item := range getItems()?is not yet supported. This limitation may be removed in the future - When discarding return values, functions must have only an error return - When you don't accept any return values from a function (i.e., when using
f()?), the function must have exactly one return value of typeerror. If a function returns multiple values (e.g.,func f() (int, error)), you need to use_to discard the non-error return values:_ = f()?
These constraints ensure the generated Go code remains clean, readable, and identical to hand-written code.
- Implement a Go-compatible command-line tool that supports all Go flags and commands, with the only difference being that it preprocesses all
.mygofiles to.gofiles before running compile or test operations
