mirror of
https://github.com/golang/go
synced 2024-11-12 07:40:23 -07:00
430d462391
also fix a pedantry in the language design faq. R=rsc DELTA=113 (94 added, 16 deleted, 3 changed) OCL=35922 CL=35928
432 lines
18 KiB
HTML
432 lines
18 KiB
HTML
<!-- The Go Programming Language Design FAQ -->
|
|
|
|
<h2 id="origins">Origins</h2>
|
|
|
|
<h3 id="history">
|
|
What is the history of the project?</h3>
|
|
<p>
|
|
Robert Griesemer, Rob Pike and Ken Thompson started sketching the
|
|
goals for a new language on the white board on September 21, 2007.
|
|
Within a few days the goals had settled into a plan to do something
|
|
and a fair idea of what it would be. Design continued part-time in
|
|
parallel with unrelated activities. By January 2008, Ken started work
|
|
on a compiler with which to explore ideas; it generated C code as its
|
|
output. By mid-year the language had become a full-time project and
|
|
had settled enough to attempt a production compiler. Meanwhile, Ian
|
|
Taylor had read the draft specification and written an independent GCC
|
|
front end. Russ Cox joined in late 2008 and helped move the language
|
|
and libraries from prototype to reality.
|
|
</p>
|
|
|
|
<h3 id="creating_a_new_language">
|
|
Why are you creating a new language?</h3>
|
|
<p>
|
|
Go was born out of frustration with existing languages and
|
|
environments for systems programming. Programming had become too
|
|
difficult and the choice of languages was partly to blame. One had to
|
|
choose either efficient compilation, efficient execution, or ease of
|
|
programming; all three were not available in the same commonly
|
|
available language. Programmers who could were choosing ease over
|
|
safety and efficiency by moving to dynamically typed languages such as
|
|
Python and JavaScript rather than C++ or, to a lesser extent, Java.
|
|
</p>
|
|
<p>
|
|
Go is an attempt to combine the ease of programming of an interpreted,
|
|
dynamically typed
|
|
language with the efficiency and type safety of a compiled language.
|
|
It also aims to be modern, with support for networked and multicore
|
|
computing. Finally, it is intended to be <i>fast</i>: it should take
|
|
at most a few seconds to build a large executable on a single computer.
|
|
To meet these goals required addressing a number of
|
|
linguistic issues: an expressive but lightweight type system;
|
|
concurrency and garbage collection; rigid dependency specification;
|
|
and so on. These cannot be addressed well by libraries or tools; a new
|
|
language was called for.
|
|
</p>
|
|
|
|
|
|
<h3 id="ancestors">
|
|
What are Go's ancestors?</h3>
|
|
<p>
|
|
Go is mostly in the C family (basic syntax),
|
|
with significant input from the Pascal/Modula/Oberon
|
|
family (declarations, packages),
|
|
plus some ideas from languages
|
|
inspired by Tony Hoare's CSP,
|
|
such as Newsqueak and Limbo (concurrency).
|
|
However, it is a new language across the board.
|
|
In every respect the language was designed by thinking
|
|
about what programmers do and how to make programming, at least the
|
|
kind of programming we do, more effective, which means more fun.
|
|
</p>
|
|
|
|
<h3 id="principles">
|
|
What are the guiding principles in the design?</h3>
|
|
<p>
|
|
Programming today involves too much bookkeeping, repetition, and
|
|
clerical work. As Dick Gabriel says, “Old programs read
|
|
like quiet conversations between a well-spoken research worker and a
|
|
well-studied mechanical colleague, not as a debate with a compiler.
|
|
Who'd have guessed sophistication bought such noise?”
|
|
The sophistication is worthwhile—no one wants to go back to
|
|
the old languages—but can it be more quietly achieved?
|
|
</p>
|
|
<p>
|
|
Go attempts to reduce the amount of typing in both senses of the word.
|
|
Throughout its design, we have tried to reduce clutter and
|
|
complexity. There are no forward declarations and no header files;
|
|
everything is declared exactly once. Initialization is expressive,
|
|
automatic, and easy to use. Syntax is clean and light on keywords.
|
|
Stuttering (<code>foo.Foo* myFoo = new(foo.Foo)</code>) is reduced by
|
|
simple type derivation using the <code>:=</code>
|
|
declare-and-initialize construct. And perhaps most radically, there
|
|
is no type hierarchy: types just <i>are</i>, they don't have to
|
|
announce their relationships. These simplifications allow Go to be
|
|
expressive yet comprehensible without sacrificing, well, sophistication.
|
|
</p>
|
|
<p>
|
|
Another important principle is to keep the concepts orthogonal.
|
|
Methods can be implemented for any type; structures represent data;
|
|
interfaces represent abstraction; and so on. Orthogonality makes it
|
|
easier to understand what happens when things combine.
|
|
</p>
|
|
|
|
|
|
<h2 id="change_from_c">Changes from C</h2>
|
|
|
|
<h3 id="different_syntax">
|
|
Why is the syntax so different from C?</h3>
|
|
<p>
|
|
Other than declaration syntax, the differences are not major and stem
|
|
from two desires. First, the syntax should feel light, without too
|
|
many mandatory keywords, repetition, or arcana. Second, the language
|
|
has been designed to be easy to analyze
|
|
and can be parsed without a symbol table. This makes it much easier
|
|
to build tools such as debuggers, dependency analyzers, automated
|
|
documentation extractors, IDE plug-ins, and so on. C and its
|
|
descendants are notoriously difficult in this regard.
|
|
</p>
|
|
|
|
<h3 id="declarations_backwards">
|
|
Why are declarations backwards?</h3>
|
|
<p>
|
|
They're only backwards if you're used to C. In C, the notion is that a
|
|
variable is declared like an expression denoting its type, which is a
|
|
nice idea, but the type and expression grammars don't mix very well and
|
|
the results can be confusing; consider function pointers. Go mostly
|
|
separates expression and type syntax and that simplifies things (using
|
|
prefix <code>*</code> for pointers is an exception that proves the rule). In C,
|
|
the declaration
|
|
</p>
|
|
<pre>
|
|
int* a, b;
|
|
</pre>
|
|
<p>
|
|
declares <code>a</code> to be a pointer but not <code>b</code>; in Go
|
|
</p>
|
|
<pre>
|
|
var a, b *int;
|
|
</pre>
|
|
<p>
|
|
declares both to be pointers. This is clearer and more regular.
|
|
Also, the <code>:=</code> short declaration form argues that a full variable
|
|
declaration should present the same order as <code>:=</code> so
|
|
</p>
|
|
<pre>
|
|
var a uint64 = 1;
|
|
</pre>
|
|
has the same effect as
|
|
<pre>
|
|
a := uint64(1);
|
|
</pre>
|
|
<p>
|
|
Parsing is also simplified by having a distinct grammar for types that
|
|
is not just the expression grammar; keywords such as <code>func</code>
|
|
and <code>chan</code> keep things clear.
|
|
</p>
|
|
|
|
<h3 id="no_pointer_arithmetic">
|
|
Why is there no pointer arithmetic?</h3>
|
|
<p>
|
|
Safety. Without pointer arithmetic it's possible to create a
|
|
language that can never derive an illegal address that succeeds
|
|
incorrectly. Compiler and hardware technology have advanced to the
|
|
point where a loop using array indices can be as efficient as a loop
|
|
using pointer arithmetic. Also, the lack of pointer arithmetic can
|
|
simplify the implementation of the garbage collector.
|
|
</p>
|
|
|
|
<h3 id="inc_dec">
|
|
Why are <code>++</code> and <code>--</code> statements and not expressions? And why postfix, not prefix?</h3>
|
|
<p>
|
|
Without pointer arithmetic, the convenience value of pre- and postfix
|
|
increment operators drops. By removing them from the expression
|
|
hierarchy altogether, expression syntax is simplified and the messy
|
|
issues around order of evaluation of <code>++</code> and <code>--</code>
|
|
(consider <code>f(i++)</code> and <code>p[i] = q[++i]</code>)
|
|
are eliminated as well. The simplification is
|
|
significant. As for postfix vs. prefix, either would work fine but
|
|
the postfix version is more traditional; insistence on prefix arose
|
|
with the STL, a library for a language whose name contains, ironically, a
|
|
postfix increment.
|
|
</p>
|
|
|
|
<h3 id="garbage_collection">
|
|
Why do garbage collection? Won't it be too expensive?</h3>
|
|
<p>
|
|
One of the biggest sources of bookkeeping in systems programs is
|
|
memory management. We feel it's critical to eliminate that
|
|
programmer overhead, and advances in garbage collection
|
|
technology in the last few years give us confidence that we can
|
|
implement it with low enough overhead and no significant
|
|
latency. (The current implementation is a plain mark-and-sweep
|
|
collector but a replacement is in the works.)
|
|
</p>
|
|
<p>
|
|
Another point is that a large part of the difficulty of concurrent
|
|
and multi-threaded programming is memory management;
|
|
as objects get passed among threads it becomes cumbersome
|
|
to guarantee they become freed safely.
|
|
Automatic garbage collection makes concurrent code far easier to write.
|
|
Of course, implementing garbage collection in a concurrent environment is
|
|
itself a challenge but meeting it once rather than in every
|
|
program helps everyone.
|
|
</p>
|
|
<p>
|
|
Finally, concurrency aside, garbage collection makes interfaces
|
|
simpler because they don't need to specify how memory is managed across them.
|
|
</p>
|
|
|
|
<h2 id="absent_features">Absent features</h2>
|
|
|
|
<h3 id="generics">
|
|
Why does Go not have generic types?</h3>
|
|
<p>
|
|
Generics may well be added at some point. We don't feel an urgency for
|
|
them, although we understand some programmers do.
|
|
</p>
|
|
<p>
|
|
Generics are convenient but they come at a cost in
|
|
complexity in the type system and run-time. We haven't yet found a
|
|
design that gives value proportionate to the complexity, although we
|
|
continue to think about it. Meanwhile, Go's built-in maps and slices,
|
|
plus the ability to use the empty interface to construct containers
|
|
(with explicit unboxing) mean in many cases it is possible to write
|
|
code that does what generics would enable, if less smoothly.
|
|
</p>
|
|
<p>
|
|
This remains an open issue.
|
|
</p>
|
|
|
|
<h3 id="exceptions">
|
|
Why does Go not have exceptions?</h3>
|
|
<p>
|
|
Exceptions are a similar story. A number of designs for exceptions
|
|
have been proposed but each adds significant complexity to the
|
|
language and run-time. By their very nature, exceptions span functions and
|
|
perhaps even goroutines; they have wide-ranging implications. There
|
|
is also concern about the effect they would have on the
|
|
libraries. They are, by definition, exceptional yet experience with
|
|
other languages that support them show they have profound effect on
|
|
library and interface specification. It would be nice to find a design
|
|
that allows them to be truly exceptional without encouraging common
|
|
errors to turn into special control flow requiring every programmer to
|
|
compensate.
|
|
</p>
|
|
<p>
|
|
Like generics, exceptions remain an open issue.
|
|
</p>
|
|
|
|
<h3 id="assertions">
|
|
Why does Go not have assertions?</h3>
|
|
<p>
|
|
This is answered in the general <a href="go_faq.html#Where_is_assert">FAQ</a>.
|
|
</p>
|
|
|
|
<h2 id="types">Types</h2>
|
|
|
|
<h3 id="inheritance">
|
|
Why is there no type inheritance?</h3>
|
|
<p>
|
|
Object-oriented programming, at least in the best-known languages,
|
|
involves too much discussion of the relationships between types,
|
|
relationships that often could be derived automatically. Go takes a
|
|
different approach.
|
|
</p>
|
|
<p>
|
|
Rather than requiring the programmer to declare ahead of time that two
|
|
types are related, in Go a type automatically satisfies any interface
|
|
that specifies a subset of its methods. Besides reducing the
|
|
bookkeeping, this approach has real advantages. Types can satisfy
|
|
many interfaces at once, without the complexities of traditional
|
|
multiple inheritance.
|
|
Interfaces can be very lightweight—having one or even zero methods
|
|
in an interface can express useful concepts.
|
|
Interfaces can be added after the fact if a new idea comes along
|
|
or for testing—without annotating the original types.
|
|
Because there are no explicit relationships between types
|
|
and interfaces, there is no type hierarchy to manage.
|
|
</p>
|
|
<p>
|
|
It's possible to use these ideas to construct something analogous to
|
|
type-safe Unix pipes. For instance, see how <code>fmt.Fprintf</code>
|
|
enables formatted printing to any output, not just a file, or how the
|
|
<code>bufio</code> package can be completely separate from file I/O,
|
|
or how the <code>crypto</code> packages stitch together block and
|
|
stream ciphers. All these ideas stem from a single interface
|
|
(<code>io.Writer</code>) representing a single method
|
|
(<code>Write</code>). And that's only scratching the surface.
|
|
</p>
|
|
<p>
|
|
It takes some getting used to but this implicit style of type
|
|
dependency is one of the most exciting things about Go.
|
|
</p>
|
|
|
|
<h3 id="methods_on_basics">
|
|
Why is <code>len</code> a function and not a method?</h3>
|
|
<p>
|
|
We debated this issue but decided
|
|
implementing <code>len</code> and friends as functions was fine in practice and
|
|
didn't complicate questions about the interface (in the Go type sense)
|
|
of basic types.
|
|
</p>
|
|
|
|
<h3 id="overloading">
|
|
Why does Go not support overloading of methods and operators?</h3>
|
|
<p>
|
|
Method dispatch is simplified if it doesn't need to do type matching as well.
|
|
Experience with other languages told us that having a variety of
|
|
methods with the same name but different signatures was occasionally useful
|
|
but that it could also be confusing and fragile in practice. Matching only by name
|
|
and requiring consistency in the types was a major simplifying decision
|
|
in Go's type system.
|
|
</p>
|
|
<p>
|
|
Regarding operator overloading, it seems more a convenience than an absolute
|
|
requirement. Again, things are simpler without it.
|
|
</p>
|
|
|
|
<h2 id="values">Values</h2>
|
|
|
|
<h3 id="conversions">
|
|
Why does Go not provide implicit numeric conversions?</h3>
|
|
<p>
|
|
The convenience of automatic conversion between numeric types in C is
|
|
outweighed by the confusion it causes. When is an expression unsigned?
|
|
How big is the value? Does it overflow? Is the result portable, independent
|
|
of the machine on which it executes?
|
|
It also complicates the compiler; “the usual arithmetic conversions”
|
|
are not easy to implement and inconsistent across architectures.
|
|
For reasons of portability, we decided to make things clear and straightforward
|
|
at the cost of some explicit conversions in the code.
|
|
The definition of constants in Go—arbitrary precision values free
|
|
of signedness and size annotations—ameliorates matters considerably,
|
|
though.
|
|
</p>
|
|
<p>
|
|
A related detail is that, unlike in C, <code>int</code> and <code>int64</code>
|
|
are distinct types even if <code>int</code> is a 64-bit type. The <code>int</code>
|
|
type is generic; if you care about how many bits an integer holds, Go
|
|
encourages you to be explicit.
|
|
</p>
|
|
|
|
<h3 id="builtin_maps">
|
|
Why are maps built in?</h3>
|
|
<p>
|
|
The same reason strings are: they are such a powerful and important data
|
|
structure that providing one excellent implementation with syntactic support
|
|
makes programming more pleasant. We believe that Go's implementation of maps
|
|
is strong enough that it will serve for the vast majority of uses.
|
|
If a specific application can benefit from a custom implementation, it's possible
|
|
to write one but it will not be as convenient to use; this seems a reasonable tradeoff.
|
|
</p>
|
|
|
|
|
|
<h3 id="map_keys">
|
|
Why don't maps allow structs and arrays as keys?</h3>
|
|
<p>
|
|
Map lookup requires an equality operator, which structs and arrays do not implement.
|
|
They don't implement equality because equality is not well defined on such types;
|
|
there are multiple considerations involving shallow vs. deep comparison, pointer vs.
|
|
value comparison, how to deal with recursive structures, and so on.
|
|
We may revisit this issue—and implementing equality for structs and arrays
|
|
will not invalidate any existing programs—but without a clear idea of what
|
|
equality of structs and arrays should mean, it was simpler to leave it out for now.
|
|
</p>
|
|
|
|
<h3 id="references">
|
|
Why are maps, slices, and channels references while arrays are values?</h3>
|
|
<p>
|
|
There's a lot of history on that topic. Early on, maps and channels
|
|
were syntactically pointers and it was impossible to declare or use a
|
|
non-pointer instance. Also, we struggled with how arrays should work.
|
|
Eventually we decided that the strict separation of pointers and
|
|
values made the language harder to use. Introducing reference types,
|
|
including slices to handle the reference form of arrays, resolved
|
|
these issues. Reference types add some regrettable complexity to the
|
|
language but they have a large effect on usability: Go became a more
|
|
productive, comfortable language when they were introduced.
|
|
</p>
|
|
|
|
<h2 id="concurrency">Concurrency</h2>
|
|
|
|
<h3 id="csp">
|
|
Why build concurrency on the ideas of CSP?</h3>
|
|
<p>
|
|
Concurrency and multi-threaded programming have a reputation
|
|
for difficulty. We believe the problem is due partly to complex
|
|
designs such as pthreads and partly to overemphasis on low-level details
|
|
such as mutexes, condition variables, and even memory barriers.
|
|
Higher-level interfaces enable much simpler code, even if there are still
|
|
mutexes and such under the covers.
|
|
</p>
|
|
<p>
|
|
One of the most successful models for providing high-level linguistic support
|
|
for concurrency comes from Hoare's Communicating Sequential Processes, or CSP.
|
|
Occam and Erlang are two well known languages that stem from CSP.
|
|
Go's concurrency primitives derive from a different part of the family tree
|
|
whose main contribution is the powerful notion of channels as first class objects.
|
|
</p>
|
|
|
|
<h3 id="goroutines">
|
|
Why goroutines instead of threads?</h3>
|
|
<p>
|
|
Goroutines are part of making concurrency easy to use. The idea, which has
|
|
been around for a while, is to multiplex independently executing
|
|
functions—coroutines, really—onto a set of threads.
|
|
When a coroutine blocks, such as by calling a blocking system call,
|
|
the run-time automatically moves other coroutines on the same operating
|
|
system thread to a different, runnable thread so they won't be blocked.
|
|
The programmer sees none of this, which is the point.
|
|
The result, which we call goroutines, can be very cheap: unless they spend a lot of time
|
|
in long-running system calls, they cost little more than the memory
|
|
for the stack.
|
|
</p>
|
|
<p>
|
|
To make the stacks small, Go's run-time uses segmented stacks. A newly
|
|
minted goroutine is given a few kilobytes, which is almost always enough.
|
|
When it isn't, the run-time allocates (and frees) extension segments automatically.
|
|
The overhead averages about three cheap instructions per function call.
|
|
It is practical to create hundreds of thousands of goroutines in the same
|
|
address space. If goroutines were just threads, system resources would
|
|
run out at a much smaller number.
|
|
</p>
|
|
|
|
<h3 id="atomic_maps">
|
|
Why are map operations not defined to be atomic?</h3>
|
|
|
|
<p>
|
|
After long discussion it was decided that the typical use of maps did not require
|
|
safe access from multiple threads, and in those cases where it did, the map was
|
|
probably part of some larger data structure or computation that was already
|
|
synchronized. Therefore requiring that all map operations grab a mutex would slow
|
|
down most programs and add safety to few. This was not an easy decision,
|
|
however, since it means uncontrolled map access can crash the program.
|
|
</p>
|
|
|
|
<p>
|
|
The language does not preclude atomic map updates. When required, such
|
|
as when hosting an untrusted program, the implementation could interlock
|
|
map access.
|
|
</p>
|