From eaf6a344b7af5cb81fd6dbfe196371c16f4dad42 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 6 Jul 2009 15:15:56 -0700 Subject: [PATCH] a few edits and simplifications. R=rsc DELTA=248 (40 added, 108 deleted, 100 changed) OCL=31211 CL=31211 --- doc/effective_go.html | 295 ++++++++++++++++-------------------------- 1 file changed, 113 insertions(+), 182 deletions(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index a4d4ed31dbc..2d963fd83b8 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -2,27 +2,21 @@

Introduction

-Go is a new programming language. -It eliminates some of the pitfalls in languages -like C++ and Java but introduces other ones. -Many remain the same. -This page gives tips for writing clear, idiomatic Go code +This document gives tips for writing clear, idiomatic Go code and points out common mistakes to avoid. It augments the language specification and the tutorial, both of which you -should be familiar with. +should read first.

-

Read

+

Read good code

-The first step to improving as a writer is to read. -This step is as necessary for programming as it is for prose, -and it is skipped as often by programmers as by writers. +The first step towards learning to write good code is to read good code. The Go package sources are intended to serve not only as the core library but also as examples of how to -use the language. Read them. +use the language. Read them and follow their example.

Be consistent

@@ -30,11 +24,10 @@ use the language. Read them.

Consistency makes programs easy to read. If a program says the same thing twice, -it should say it the same way both times, -so that the parallel structure is clear. -Conversely, if two different sections of +it should say it the same way both times. +Conversely, if two different sections of a program look different, the reader will -expect them to be doing different things. +expect them to do different things.

@@ -58,43 +51,42 @@ for i := n-1; i >= 0; i-- {

The convention in most languages (including Go) -is to count up unless doing so would be incorrect. -A loop that counts down implicitly says “there's -a specific reason to count down here; this situation is special.” -A reader who finds a program in which half the -loops count up and the other half count down +is to count up unless to do so would be incorrect. +A loop that counts down implicitly says “something +special is happening here.” +A reader who finds a program in which some +loops count up and the rest count down will spend time trying to understand why. -A programmer who inserts counting-down -loops for variety wastes the reader's time. +Don't run loops backwards unless it's necessary.

-Loop direction is hardly the only +Loop direction is just one programming decision which a programmer -might want to use to be distinctive: +may be tempted to be distinctive: tabs or spaces, choice of variable names, choice of method names, whether a type has a constructor, what tests look like, and on and on. As in the loop example, inconsistency sows confusion, and wastes time. -Why is this variable called n here and cnt here? +Why is this variable called n here and cnt there? Why is the Log constructor CreateLog when -the Vector constructor is NewVector? +the List constructor is NewList? Why is this data structure initialized using -a structure literal when this other one +a structure literal when that one is initialized using individual assignments? -Why is this idiom used here but not there? -And on and on. +And so on. These questions distract from the important one: what does the code do? +Moreover, internal consistency is important not only within a single file, +but also within the the surrounding source files. Being consistent about little things lets readers concentrate on big ones.

-This document describes how to use Go effectively. -Equally important, it describes how to use Go idiomatically, -so that a Go programmer seeing your code for +This document describes how to use Go effectively and idiomatically +so that a programmer seeing your code for the first time can focus on what it does and not why it is inconsistent with typical Go practices. Consistency trumps every item listed below. @@ -102,14 +94,7 @@ When editing code, read the surrounding context and try to mimic it as much as possible, even if it disagrees with the rules here. It should not be possible to tell which lines -you wrote or edited. -

- -

-Internal consistency is important in a single file, -but source files do not exist in isolation. -Code must be consistent with the surrounding source file as well, -or the same problems arise. +you wrote or edited based on style alone.

Formatting

@@ -117,16 +102,16 @@ or the same problems arise.

Formatting issues are the most contentious but the least consequential. -People adapt quite well to different formatting styles, -even if at first the styles “look weird.” -The most important consideration is that if everyone -uses the same formatting, then a reader picking up an -unfamiliar piece of code can focus on what -the code does instead of what it looks like. -Most of the local formatting style can and should be -picked up by reading existing Go programs (see above). -The following are the most common issues -that Google programmers run into. +People adapt to different formatting styles, +even if at first the styles “look weird,” +but they shouldn't be asked to. +Everyone +should use the same formatting; as in English, +consistent punctuation and spacing make the +text easier to read. +Most of the local formatting style can be +picked up by reading existing Go programs (see above), +but to make them explicit here are some common points.

Use tabs

@@ -138,9 +123,7 @@ The local style is to use tabs, not spaces, for indentation.

Trim trailing white space

-Files should not contain trailing white space at the end of lines. -The script /home/rsc/bin/g4ws removes trailing -whitespace from all open files in the current g4 client. +There should be no trailing white space at the end of lines.

Don't wrap lines mechanically

@@ -148,14 +131,14 @@ whitespace from all open files in the current g4 client.

Go has no 80-character limit. Don't bother with fancy line wrapping just because a line is wider than a punched card. -If you must wrap a line, indent with a single tab. +If you must wrap a line, indent with an extra tab.

-

Omit parentheses

+

Omit parentheses in control structures

Go does not require parentheses around the expression following the for, if, range, -and switch keywords. +switch, and return keywords.

Use line comments

@@ -163,7 +146,7 @@ and switch keywords.

Go provides C-style /* */ block comments and C++-style // line comments. -The local style is to use line comments by default, +Use line comments by default, reserving block comments for top-level package comments and commenting out large swaths of code.

@@ -173,8 +156,10 @@ and commenting out large swaths of code.

If a comment immediately precedes a top-level declaration, the Go documentation server +(TODO: that's not a public URL.) uses that comment as the documentation -for the constant, function, package, type or variable being declared. +for the constant, function, method, package, type or variable being declared. +These are called doc comments. To detach a comment from a declaration, insert a blank line between them.

@@ -182,6 +167,9 @@ line between them.

Every exported (capitalized) name in a program should have a doc comment, as should the package declaration itself. +If a name appears multiple times due to forward declarations +or appearance in multiple source files within a package, only +one instance requires a doc comment, and any one will do.

@@ -198,16 +186,6 @@ starts with the name being declared: func Quote(s string) string { -

-instead of: -

- -
-/* not Go style */
-// Return a double-quoted Go string literal representing s....
-func Quote(s string) string {
-
-

The complete English sentence form admits a wider variety of automated presentations. @@ -223,7 +201,7 @@ Don't use fancy formattings that depend on fixed-width fonts. In particular, don't assume that a single space is the same width as every other character. If you need to make a columnated table, use tabs to separate -the columns and the pretty printer (in progress) will make +the columns and the pretty printer will make sure the columns are lined up properly in the output.

@@ -239,21 +217,18 @@ sections in a file, use a simple block comment: */ -

-instead of: -

+or -
-/* not Go style */
-//////////////////////////////////////////////////////////////////////
-// Helper routines for simplifying the fetching of optional fields of basic type.
-// If the field is missing, they return the zero for the type.
+
+/*
+    Helper routines for simplifying the fetching of optional fields of basic type.
+    If the field is missing, they return the zero for the type.
+ */
 

-Comments are text, not HTML, and not any kind of markup. +Comments are text, not HTML; they contain no markup. Refrain from ASCII embellishment like *this* or /this/. -As usual, read the Go sources for examples.

Names

@@ -263,40 +238,38 @@ As usual, read the Go sources for examples.

Go uses the case of the first letter in a name to decide whether the name is visible in other packages. -In Go, multiword names use MixedCaps or mixedCaps +Multiword names use MixedCaps or mixedCaps rather than underscores.

Use short package names

-Package names are lowercase single-word names: +Package names are lower case single-word names: there should be no need for underscore or mixedCaps. The package name is conventionally the base name of the source directory: the package in src/pkg/container/vector -is installed as "container/vector" but has name vector, +is installed as "container/vector" but has name vector, not container_vector and not containerVector. The package name is only the default name used -when importing the package; it need not be a unique -identifier. +when importing the package; it need not be unique +across all source code.

-

Avoid lengthy names

+

Avoid long names

A name's length should not exceed its information content. For a function-local variable in scope only for a few lines, the name i conveys just as much information as index or idx and is easier to read. -On the same note, i and j are better pair of names for -index variables than i1 and i2 (or, worse, index1 and index2), -because they are easier to tell apart when reading -the program quickly. +Letters are easier to distinguish than numbers; use i and j +not i1 and i2.

-Exported names must convey more information, -because they appear in a larger variety of contexts. +Exported names must convey more information +because they appear far from their origin. Even so, longer names are not always better, and the package name can help convey information: the buffered Reader is bufio.Reader, not bufio.BufReader. @@ -313,10 +286,7 @@ to use them without documentation.

One-method interfaces are conventionally named by the method name plus the -er suffix: Reader, -Writer, Formatter. Using an interface name distinct -from the method name keeps an anonymous struct -field of type Reader from conflicting with its own -Read method. +Writer, Formatter.

Use canonical names

@@ -328,7 +298,7 @@ don't give your method one of those names unless it has the same signature and meaning. Conversely, if your type implements a method with the same meaning as a method on a well-known type, -give it the same name and, equally important, the same signature. +give it the same name and signature.

@@ -370,11 +340,7 @@ hdr, body, checksum := buf[0:20], buf[20:len(buf)-4], buf[len(buf)-4:len(buf)];

If an if body doesn't flow off the end of the body—that is, the body ends in break, continue, -goto, or return—it is preferable to omit the else. -

- -

-For example: +goto, or return—omit the else.

@@ -383,40 +349,43 @@ if err != nil {
 	return err;
 }
 codeUsing(f);
-f.Close();
-moreCode();
 
-

-is preferable to: - -

-/* not Go style */
-if f, err := os.Open(name, os.O_RDONLY, 0); err != nil {
-	return err;
-} else {
-	codeUsing(f);
-	f.Close();
-}
-moreCode();
-
- -

-The first form -avoids unnecessary indentation -and makes it clear that moreCode() -only runs when f.Close() does. -

-

Switch

-Go's switch is more powerful than C's. +Go's switch is more general than C's. When an if-else if-else chain has three or more bodies, or an if condition has a long list of alternatives, -consider rewriting it using switch. +it will be clearer if rewritten as a switch.

+go/src/pkg/http/url.go: +
+func unhex(c byte) byte {
+    switch {
+    case '0' <= c && c <= '9':
+        return c - '0'
+    case 'a' <= c && c <= 'f':
+        return c - 'a' + 10
+    case 'A' <= c && c <= 'F':
+        return c - 'A' + 10
+    }
+    return 0
+}
+
+ +go/src/pkg/http/url.go: +
+func shouldEscape(c byte) bool {
+    switch c {
+    case ' ', '?', '&', '=', '#', '+', '%':
+        return true
+    }
+    return false
+}
+
+ go/src/pkg/bytes/bytes.go:
 // Compare returns an integer comparing the two byte arrays lexicographically.
@@ -440,44 +409,18 @@ func Compare(a, b []byte) int {
 }
 
-go/src/pkg/http/url.go: -
-func unhex(c byte) byte {
-    switch {
-    case '0' <= c && c <= '9':
-        return c - '0'
-    case 'a' <= c && c <= 'f':
-        return c - 'a' + 10
-    case 'A' <= c && c <= 'F':
-        return c - 'A' + 10
-    }
-    return 0
-}
-
- -go/src/pkg/http/url.go: -
-func shouldEscape(c byte) bool {
-    switch c {
-    case ' ', '?', '&', '=', '#', '+', '%':
-        return true
-    }
-    return false
-}
-
-

Functions

Omit needless wrappers

-Functions are great for factoring out common functionality. -If a function is only called once, -ask whether the function is really necessary, +Functions are great for factoring out common code, but +if a function is only called once, +ask whether it is necessary, especially if it is just a short wrapper around another function. -This style runs rampant in C++ code: wrappers +This style is rampant in C++ code: wrappers call wrappers that call wrappers that call wrappers. -Doing this hinders people trying to understand the program, +This style hinders people trying to understand the program, not to mention computers trying to execute it.

@@ -486,17 +429,15 @@ not to mention computers trying to execute it.

If a function must return multiple values, it can do so directly. -The C “pass in a pointer to a return value” -idiom is dead. +There is no need to pass a pointer to a return value.

-

Errors

Handle errors first

-Errors tend to be simpler than non-error cases, +Error cases tend to be simpler than non-error cases, and it helps readability when the non-error flow of control is always down the page. Also, error cases tend to end in jumps, @@ -504,27 +445,17 @@ so that there is no need for an explicit else.

+if len(name) == 0 {
+	return;
+}
+if IsDir(name) {
+	return;
+}
 f, err := os.Open(name, os.O_RDONLY, 0);
 if err != nil {
-	return err;
+	return;
 }
 codeUsing(f);
-f.Close();
-moreCode();
-
- -is preferable to: - -
-/* not Go style */
-f, err := os.Open(name, os.O_RDONLY, 0);
-if err == nil {
-	codeUsing(f);
-	f.Close();
-} else {
-	return err;
-}
-moreCode();
 

Return os.Error, not bool

@@ -581,7 +512,7 @@ func NewFile(fd int, name string) *File {

Packages that export only a single type sometimes shorten NewTypeName to New; -for example, the vector constructor is +the vector constructor is vector.New, not vector.NewVector.

@@ -637,14 +568,14 @@ For example, both crc32.NewIEEE() and adler32.New() return type hash.Hash32. Substituting the CRC-32 algorithm for Adler-32 in a Go program requires only changing the constructor call: -the rest of the code cannot distinguish the two algorithms. +the rest of the code is unaffected by the change of algorithm.

-

Use interface adapters to expand an implementation

+

Use interface adapters to expand an implementation

XXX -

Use anonymous fields to incorporate an implementation

+

Use anonymous fields to incorporate an implementation

XXX