diff --git a/doc/go_faq.html b/doc/go_faq.html index 0bb3eef76c..d7d23567e9 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -8,6 +8,7 @@ What is the purpose of the project?
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: +
-Many others have contributed ideas, discussions, and code. +Go became a public open source project on November 10, 2009. +Many people from the community have contributed ideas, discussions, and code.
-Go takes a different approach. Instead of exceptions, it has a couple +Go takes a different approach. For plain error handling, Go's multi-value +returns make it easy to report an error without overloading the return value. +A +canonical error type, coupled +with Go's other features, makes error +handling pleasant but quite different from that in other languages. +
+ ++Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient @@ -372,7 +382,7 @@ Why build concurrency on the ideas of CSP? 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. +such as mutexes, condition variables, and memory barriers. Higher-level interfaces enable much simpler code, even if there are still mutexes and such under the covers.
@@ -390,14 +400,14 @@ Why goroutines instead of threads?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. +functions—coroutines—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. +for the stack, which is just a few kilobytes.
@@ -473,8 +483,8 @@ 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 very lightweight—an interface with +one or even zero methods can express a useful concept. 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 @@ -494,7 +504,7 @@ stream ciphers. All these ideas stem from a single interface
It takes some getting used to but this implicit style of type -dependency is one of the most exciting things about Go. +dependency is one of the most productive things about Go.
+Consider this simple interface to represent an object that can compare +itself with another value: +
+ ++type Equaler interface { + Equal(Equaler) bool +} ++ +
+and this type, T
:
+
+type T int +func (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler ++ +
+Unlike the analogous situation in some polymorphic type systems,
+T
does not implement Equaler
.
+The argument type of T.Equal
is T
,
+not literally the required type Equaler
.
+
+In Go, the type system does not promote the argument of
+Equal
; that is the programmer's responsibility, as
+illustrated by the type T2
, which does implement
+Equaler
:
+
+type T2 int +func (t T2) Equal(u Equaler) bool { return t == u.(T2) } // satisfies Equaler ++ +
+Even this isn't like other type systems, though, because in Go any
+type that satisfies Equaler
could be passed as the
+argument to T2.Equal
, and at run time we must
+check that the argument is of type T2
.
+Some languages arrange to make that guarantee at compile time.
+
+A related example goes the other way: +
+ ++type Opener interface { + Open(name) Reader +} + +func (t T3) Open() *os.File ++ +
+In Go, T3
does not satisfy Opener
,
+although it might in another language.
+
+While it is true that Go's type system does less for the programmer +in such cases, the lack of subtyping makes the rules about +interface satisfaction very easy to state: are the function's names +and signatures exactly those of the interface? +Go's rule is also easy to implement efficiently. +We feel these benefits offset the lack of +automatic type promotion. Should Go one day adopt some form of generic +typing, we expect there would be a way to express the idea of these +examples and also have them be statically checked. +
+-func (s *MyStruct) someMethod() { } // method on pointer -func (s MyStruct) someMethod() { } // method on value +func (s *MyStruct) pointerMethod() { } // method on pointer +func (s MyStruct) valueMethod() { } // method on value
+For programmers unaccustomed to pointers, the distinction between these
+two examples can be confusing, but the situation is actually very simple.
When defining a method on a type, the receiver (s
in the above
-example) behaves exactly is if it were an argument to the method. Define the
-method on a pointer type if you need the method to modify the data the receiver
-points to. Otherwise, it is often cleaner to define the method on a value type.
+example) behaves exactly as if it were an argument to the method.
+Whether to define the receiver as a value or as a pointer is the same
+question, then, as whether a function argument should be a value or
+a pointer.
+There are several considerations.
+First, and most important, does the method need to modify the
+receiver?
+If it does, the receiver must be a pointer.
+(Slices and maps are reference types, so their story is a little
+more subtle, but for instance to change the length of a slice
+in a method the receiver must still be a pointer.)
+In the examples above, if pointerMethod
modifies
+the fields of s
,
+the caller will see those changes, but valueMethod
+is called with a copy of the caller's argument (that's the definition
+of passing a value), so changes it makes will be invisible to the caller.
+
+By the way, pointer receivers are identical to the situation in Java, +although in Java the pointers are hidden under the covers; it's Go's +value receivers that are unusual. +
+ +
+Second is the consideration of efficiency. If the receiver is large,
+a big struct
for instance, it will be much cheaper to
+use a pointer receiver.
+
+Next is consistency. If some of the methods of the type must have +pointer receivers, the rest should too, so the method set is +consistent regardless of how the type is used. +See the section on method sets +for details. +
+ +
+For types such as basic types, slices, and small structs
,
+a value receiver is very cheap so unless the semantics of the method
+requires a pointer, a value receiver is efficient and clear.
+
+In any case, Go can often be very competitive. See the blog post about +profiling +Go programs for an informative example. +
chan
keep things clear.
-See the Go's Declaration Syntax article for more details. +See the article about +Go's Declaration Syntax +for more details.
+On the topic of performance, keep in mind that Go gives the programmer +considerable control over memory layout and allocation, much more than +is typical in garbage-collected languages. A careful programmer can reduce +the garbage collection overhead dramatically by using the language well; +see the article about +profiling +Go programs for a worked example, including a demonstration of Go's +profiling tools. +