A major design point of Go-2 is that it does not attempt to be fully backward compatible with Go, although the vast majority of cleanly written Go programs will compile and run perfectly under Go-2. See below for incompatible language features. Full backward binary compatibility is however guaranteed.
Go-2 adds generics. The benefits are clear: less duplicated boilerplate code and the ability to ship a general set of collection types (set, bag, map, relation, as well as specific concrete types such as list and tree) in the standard library. Go-2 preserves Go's map syntax, but introduces user-defined operators so that fewer builtins are required and map can be implemented without special support from the compiler.
Go-2 builds on Go's support for first class functions by adding some missing functional programming features: curried functions, partial function application, map/filter operations for applying functions to slices, and monads.
Go-2 also plugs Go's dependency management gap by adding relative imports (essential for centralised version control systems) and semantic versioning of imports. The version numbering format is configurable so, in addition to the usual decimal format, other formats may be used. Roman numerals are particularly intuitive to those coding in Latin character sets. A new Gradle plugin supports Go-2 projects and guarantees repeatable builds.
Go-2 exploits package versioning to introduce the notion of a module to encapsulate a group of packages and selectively export packages for use by other modules. Modules are separately compiled and dynamically linkable from Go-2 main programs.
Go eliminated many common concurrency issues by the prudent use of channels rather than data sharing. Go-2 takes this much further by introducing CSP-semantic verification at the compilation stage. It is virtually impossible to produce programs with any of the concurrency problems that remain: starvation, silent goroutine failures, infinite hidden chatter, etc. Although this extends compilation times somewhat, it makes Go-2 the perfect tool for hyper-concurrent systems. The Go-2 team is currently validating this part of the compiler (using the compiler to analyse itself), though the process is taking longer than expected.
Go-2 drops some Go language features which are usually indicative of dimness. The most notable such feature is the label. The break and continue keywords are supported, but only apply to the innermost loop and do not take a label. In a concession to Go programmers who still use the feature (e.g. here), the goto statement is supported, but in a limited form: goto takes an optional relative line number as its argument. If the line number is omitted, control flows to the next statement. Go's "select {}" is replaced by the more natural "goto 0".
Go-2 simplifies two confusing features of Go. nil values really are nil regardless of how they are initialised. Also, unexported methods may no longer be defined in exported interfaces unless they are also re-implemented local to use. Such interfaces can then be mocked, but only if their private methods are also implemented locally. This behaviour turns out to be much more intuitive.
The Go-2 compiler is written in Go-2 with semantics defined in the pure functional subset of Go-2, with monads. This approach simplifies the process of bootstrapping the compiler and, thanks to the use of a continuation monad, makes it trivial to add advanced features such as atomic panics and user defined deferrals. A Go-2 language specification will be provided for users not comfortable with functional programming. "Effective Go-2" will follow up with examples of idiomatic coding style and corrections to the language specification.
An experimental area of Go-2 is the introduction of bytecode to deliver platform-independent modules and avoid the complexities of cross-compilation. This is especially important for modules in the standard library, which would otherwise need to be compiled to multiple target architectures. The bytecode interpreter already runs reasonably efficiently but, once the project has addressed certain branding issues with the Go-2-in-time compiler (provisionally named "git"), we anticipate bytecode to deliver superior performance to compiled binaries via a couple of innovative features. Firstly, the git compiler is itself packaged as a bytecode module. Secondly, git (nicknamed "gradually-in-time" compiler by the project team) combines speculative partial recompilation with machine learning to deliver continual optimisation. These features trade off start-up speed against ultimate performance. Since the git compiler is itself subject to speculative recompilation, the performance of application code accelerates over time, as shown in the graph below:
The following features were deemed too boring for the initial release of Go-2, but are now eagerly anticipated:
- ternary ("bool ? trueValue : falseValue") and quaternary expressions ("*bool ? trueValue : falseValue ! nilValue"),
- non-shadowing short variable declaration syntax (::=) which will fail to compile if any variables are shadowed (anywhere),
- user-defined deferrals,
- the identity monad.