No major systems language has emerged in over a decade, but over that time the computing landscape has changed tremendously. There are several trends:
We believe it's worth trying again with a new language, a concurrent, garbage-collected language with fast compilation. Regarding the points above:
"Ogle" would be a good name for a Go debugger.
The 6g
(and 8g
) compiler is named in the
tradition of the Plan 9 C compilers, described in
http://plan9.bell-labs.com/sys/doc/compiler.html
(see the table in section 2).
6 is the architecture letter for amd64 (or x86-64, if you prefer).
g stands for go.
We considered doing that, but too many of the problems—lack of garbage collection, long dependency chains, nested include files, lack of concurrency awareness—are caused by the C++ language itself. We felt a viable solution required a more complete approach.
Go is an experiment. We hope adventurous users will give it a try and see if it provides a viable alternative to the status quo. Not every programmer will like it but we hope enough will find satisfaction in the approach it offers to justify further development.
There are two Go compilers, 6g
and gccgo
.
6g
uses a different calling convention and linker and can
therefore only be linked with C programs using the same convention.
There is such a C compiler but no C++ compiler. Gccgo
is a
gcc
front-end that can, with care, be linked with gcc-compiled
C or C++ programs. However, because Go is garbage-collected it will be
unwise to do so, at least naively.
Work is underway to provide a 'foreign function interface' to allow safe interoperation of languages in a running program.
Protocol buffers are supported. The next release of the protocol compiler project will include Go code generators and a Go library for them. It is still being tweaked but works well.
Every language contains novel features and omits someone's favorite feature. Go was designed with an eye on felicity of programming, speed of compilation, orthogonality of concepts, and the need to support features such as concurrency and garbage collection. Your favorite feature may be missing because it doesn't fit, because it affects compilation speed or clarity of design, or because it would make the fundamental system model too difficult.
Before you get too worried about Go not having feature X, please investigate the features that Go does have. You might find that they compensate in interesting ways for the lack of X.
This and other language design questions are answered in the separate language FAQ.
Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of "interface" in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing.
The lack of type hierarchy makes "objects" in Go feel much more lightweight than in languages such as C++ and Java.
The only way to have dynamically dispatched methods is through an interface. Methods on structs or other types are always resolved statically.
We haven't fully defined it all yet, but some details are available in the Go Memory Model specification.
One point that has come up: at least for now, maps do not guarantee atomic update from multiple threads of execution. This is not the place for a full discussion but in essence it was felt that shared maps are usually part of some larger synchronized object and forcing synchronization in the map implementation would be too costly considering how rarely it would actually help.
The sync package implements mutexes, but we hope Go programming style will encourage people to try higher-level techniques. In particular, consider structuring your program so that only one goroutine at a time is ever responsible for a particular piece of data.
Do not communicate by sharing memory. Instead, share memory by communicating.
There is a program, godoc
, written in Go, that extracts
package documentation from the source code. It can be used on the
command line or on the web. An instance is running at
http://go/go.
Eventually, there will be a small number of rules that guide things like naming, layout, and file organization. We are thinking of enforcing layout rules using a pretty-printing program that implements the rules, rather than writing a compendium of do's and don'ts that allows interpretation.
go/src/pkg
.
Makefile
by following existing examples.
make
and make test
in the affected
directories.
cd go/src/lib;
./deps.bash
to update the Make.deps file included in the Makefile.
For a new component, update the Makefile
and then run
deps.bash
.
cd go/src; ./all.bash
all.bash
succeeds (output like
"N known bugs; 0 unexpected bugs" is OK),
submit a CL.
Put all the source files for the package in a directory by themselves. Source files can refer to items from different files at will; there is no header file or need for forward declarations.
Other than being split into multiple files, the package will compile and test just like a single-file package.
Create a new file ending in _test.go
in the same directory
as your package sources. Inside that file, import "testing"
and write functions of the form
func TestFoo(t *testing.T) { ... }
Run gotest
in that directory.
That script finds the Test
functions,
builds a test binary, and runs it.
Go doesn't provide assertions. They are undeniably convenient, but our experience has been that programmers use them as a crutch to avoid thinking about proper error handling and reporting. Proper error handling means that servers continue operation after non-fatal errors instead of crashing. Proper error reporting means that errors are direct and to the point, saving the programmer from interpreting a large crash trace. Precise errors are particularly important when the programmer seeing the errors is not familiar with the code.
The same arguments apply to the use of assert()
in test programs. Proper
error handling means letting other tests run after one has failed, so
that the person debugging the failure gets a complete picture of what is
wrong. It is more useful for a test to report that
isPrime
gives the wrong answer for 2, 3, 5, and 7 (or for
2, 4, 8, and 16) than to report that isPrime
gives the wrong
answer for 2 and therefore no more tests were run. The programmer who
triggers the test failure may be someone editing the code months later
or even someone editing a different package on which the code depends.
Time invested writing a good error message now pays off later when the
test breaks.
In testing, if the amount of extra code required to write good errors seems repetitive and overwhelming, it might work better as a table-driven test instead. Unlike Java (jUnit's home language), Go has excellent support for data structure literals.
We understand that this is a point of contention. There are many things in the Go language and libraries that differ from modern practices, simply because we feel it's worth trying to do better.
Gccgo has a C++ front-end with a recursive descent parser coupled to the standard gcc back end. 6g is written in C using yacc/bison for the parser. Although it's a new program, it fits in the Plan 9 C compiler suite (http://plan9.bell-labs.com/sys/doc/compiler.html) and uses a variant of the Plan 9 loader to generate ELF binaries.
We considered writing 6g, the original Go compiler, in Go itself but elected not to do so because of the difficulties of bootstrapping and especially of open source distribution - you'd need a Go compiler to set up a Go environment. Gccgo, which came later, makes it possible to consider rewriting 6g in Go, which might well happen. (Go would be a fine language in which to implement a compiler; a native lexer and parser are already available in pkg/go.)
We also considered using LLVM for 6g but we felt it was too large and slow to meet our performance goals.
Again due to bootstrapping issues, the runtime is mostly in C (with a tiny bit of assembler) although Go is capable of implementing most of it now. Gccgo's runtime uses glibc; 6g uses a custom library, compiled with 6c (the Plan 9 C compiler) to keep the footprint under control. The version of 6c used supports segmented stacks for goroutines; work is underway to provide the same stack management in gccgo.