At Gophercon 2018, Russ Cox explained what will go into Go 2, including error handling and generics, and gave a preview of what the current proposals for the new features look like.
Announced at Gophercon 2017 last year, Go 2 aims to fix the shortcomings of the language, while keeping the same overall goals of being an effective language to develop system at scale, meaning large systems made of many interacting concurrent services, and large codebases developed by many loosely-coordinated engineers.
As Cox explained, there are three areas of improvement that consistently show up in all Go developer surveys: package management, error handling, and generics.
As InfoQ reported, modules made their appearance in Go 1.11, albeit still experimentally and subject to changes. Modules are collections of packages sharing a common import path prefix that provide an alternative to GOPATH
to locate dependencies for a project. They also are the units of versioning to guarantee that recursive dependencies are satisfied.
Speaking of error handling, says Cox, the shortcoming of Go are currently identified and understood. One problem with how Go does error handling is the way it forces too much boilerplate on the developer, as the following idiomatic pattern shows:
value, err := DoSomething()
if err != nil {
log.Println(err)
return err
}
Another related issue is Go does not explicitly foster an error handling model where enough information is passed back to the caller, including enough detail such as the file name, line number, etc. Providing that kind of detail is not hard, but it adds to the boilerplate.
To fix all of that, the current draft design for error handling in Go 2 adops a new pattern based on:
-
A
check function(...)
expression that syntactically shortens the error checking while keeping it explicit. -
A
handle
statement to define what to do when a check statement fails and making it easy to add precise error reporting in a single place.
The check/handle
combination effectively streamlines error handling, as the following example shows:
func OldErrorHandlingExample() error {
hex, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatal(err)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
data, err := parseHexdump(string(hex))
if err != nil {
log.Fatal(err)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
os.Stdout.Write(data)
return nil
}
func NewErrorHandlingExample() error {
handle err {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
hex := check ioutil.ReadAll(os.Stdin)
data := check parseHexdump(string(hex))
handle err {
// Do something specific here, if required; e.g.
// if you opened a file, close it
}
os.Stdout.Write(data)
return nil
}
It is important to take into account that handle
blocks chain lexically, and are executed from the innermost backwards up to the first one that includes a return statement.
The concept of generics is well known to the Go community from other languages that include it, such as C++, Java, etc. One key point when introducing generics in a language is how it allows you to define the parametric type and the constraints it must satisfy, for example being comparable for equality. Leaving the constraints specification out of the generics specification, i.e., having them inferred from the implementation, leads to poor interfaces that could too easily get broken during code development, says Cox.
The current draft design for generics in Go 2 uses a contract
to define the operations that a parametric type must support and that the implementation can use, for example:
contract Equal(t T) {
t == T
}
func Uniq(type T Equal)(in <-chan T) <-chan T {
...
if v != n { ... }
...
}
Current draft designs for Go 2 are still just that, drafts. Now is the time for the Go community to join in and help improve them so they can be transformed into official proposals. Development of Go 1 will not stop. In fact, according to the original plan, backwards-compatible features of Go 2 will be released incrementally as part of the Go 1 releases, as it already happened with module support in Go 1.11, and only afterwards the language will start including any feature breaking compatibility with existing code bases.