aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Souza <franciscossouza@gmail.com>2012-03-13 14:46:08 +1100
committerAndrew Gerrand <adg@golang.org>2012-03-13 14:46:08 +1100
commit6033a48b775365714be86462f7e2480e881e978b (patch)
treede545fedee4b24675b8e1cd850f8a18309a03674
parent82fc28c0f5a5af9fd18c0c49a65aa6a44ede1aa3 (diff)
downloadgo-6033a48b775365714be86462f7e2480e881e978b.tar.gz
go-6033a48b775365714be86462f7e2480e881e978b.zip
doc: add Go's declaration syntax article
Originally published on The Go Programming Language Blog, July 7, 2010. I did not put any go file in doc/progs. Shoul I include Go files with those declarations? http://blog.golang.org/2010/07/gos-declaration-syntax.html Update #2547. R=golang-dev, adg CC=golang-dev https://golang.org/cl/5795068
-rw-r--r--doc/articles/gos_declaration_syntax.html348
-rw-r--r--doc/docs.html2
-rw-r--r--doc/go_faq.html2
3 files changed, 350 insertions, 2 deletions
diff --git a/doc/articles/gos_declaration_syntax.html b/doc/articles/gos_declaration_syntax.html
new file mode 100644
index 0000000000..455cced1d5
--- /dev/null
+++ b/doc/articles/gos_declaration_syntax.html
@@ -0,0 +1,348 @@
+<!--{
+"Title": "Go's Declaration Syntax"
+}-->
+
+<p>
+Newcomers to Go wonder why the declaration syntax is different from the
+tradition established in the C family. In this post we'll compare the
+two approaches and explain why Go's declarations look as they do.
+</p>
+
+<p>
+<b>C syntax</b>
+</p>
+
+<p>
+First, let's talk about C syntax. C took an unusual and clever approach
+to declaration syntax. Instead of describing the types with special
+syntax, one writes an expression involving the item being declared, and
+states what type that expression will have. Thus
+</p>
+
+<pre>
+int x;
+</pre>
+
+<p>
+declares x to be an int: the expression 'x' will have type int. In
+general, to figure out how to write the type of a new variable, write an
+expression involving that variable that evaluates to a basic type, then
+put the basic type on the left and the expression on the right.
+</p>
+
+<p>
+Thus, the declarations
+</p>
+
+<pre>
+int *p;
+int a[3];
+</pre>
+
+<p>
+state that p is a pointer to int because '*p' has type int, and that a
+is an array of ints because a[3] (ignoring the particular index value,
+which is punned to be the size of the array) has type int.
+</p>
+
+<p>
+What about functions? Originally, C's function declarations wrote the
+types of the arguments outside the parens, like this:
+</p>
+
+<pre>
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{ /* ... */ }
+</pre>
+
+<p>
+Again, we see that main is a function because the expression main(argc,
+argv) returns an int. In modern notation we'd write
+</p>
+
+<pre>
+int main(int argc, char *argv[]) { /* ... */ }
+</pre>
+
+<p>
+but the basic structure is the same.
+</p>
+
+<p>
+This is a clever syntactic idea that works well for simple types but can
+get confusing fast. The famous example is declaring a function pointer.
+Follow the rules and you get this:
+</p>
+
+<pre>
+int (*fp)(int a, int b);
+</pre>
+
+<p>
+Here, fp is a pointer to a function because if you write the expression
+(*fp)(a, b) you'll call a function that returns int. What if one of fp's
+arguments is itself a function?
+</p>
+
+<pre>
+int (*fp)(int (*ff)(int x, int y), int b)
+</pre>
+
+<p>
+That's starting to get hard to read.
+</p>
+
+<p>
+Of course, we can leave out the name of the parameters when we declare a
+function, so main can be declared
+</p>
+
+<pre>
+int main(int, char *[])
+</pre>
+
+<p>
+Recall that argv is declared like this,
+</p>
+
+<pre>
+char *argv[]
+</pre>
+
+<p>
+so you drop the name from the <em>middle</em> of its declaration to construct
+its type. It's not obvious, though, that you declare something of type
+char *[] by putting its name in the middle.
+</p>
+
+<p>
+And look what happens to fp's declaration if you don't name the
+parameters:
+</p>
+
+<pre>
+int (*fp)(int (*)(int, int), int)
+</pre>
+
+<p>
+Not only is it not obvious where to put the name inside
+</p>
+
+<pre>
+int (*)(int, int)
+</pre>
+
+<p>
+it's not exactly clear that it's a function pointer declaration at all.
+And what if the return type is a function pointer?
+</p>
+
+<pre>
+int (*(*fp)(int (*)(int, int), int))(int, int)
+</pre>
+
+<p>
+It's hard even to see that this declaration is about fp.
+</p>
+
+<p>
+You can construct more elaborate examples but these should illustrate
+some of the difficulties that C's declaration syntax can introduce.
+</p>
+
+<p>
+There's one more point that needs to be made, though. Because type and
+declaration syntax are the same, it can be difficult to parse
+expressions with types in the middle. This is why, for instance, C casts
+always parenthesize the type, as in
+</p>
+
+<pre>
+(int)M_PI
+</pre>
+
+<p>
+<b>Go syntax</b>
+</p>
+
+<p>
+Languages outside the C family usually use a distinct type syntax in
+declarations. Although it's a separate point, the name usually comes
+first, often followed by a colon. Thus our examples above become
+something like (in a fictional but illustrative language)
+</p>
+
+<pre>
+x: int
+p: pointer to int
+a: array[3] of int
+</pre>
+
+<p>
+These declarations are clear, if verbose - you just read them left to
+right. Go takes its cue from here, but in the interests of brevity it
+drops the colon and removes some of the keywords:
+</p>
+
+<pre>
+x int
+p *int
+a [3]int
+</pre>
+
+<p>
+There is no direct correspondence between the look of [3]int and how to
+use a in an expression. (We'll come back to pointers in the next
+section.) You gain clarity at the cost of a separate syntax.
+</p>
+
+<p>
+Now consider functions. Let's transcribe the declaration for main, even
+though the main function in Go takes no arguments:
+</p>
+
+<pre>
+func main(argc int, argv *[]byte) int
+</pre>
+
+<p>
+Superficially that's not much different from C, but it reads well from
+left to right:
+</p>
+
+<p>
+<em>function main takes an int and a pointer to a slice of bytes and returns an int.</em>
+</p>
+
+<p>
+Drop the parameter names and it's just as clear - they're always first
+so there's no confusion.
+</p>
+
+<pre>
+func main(int, *[]byte) int
+</pre>
+
+<p>
+One value of this left-to-right style is how well it works as the types
+become more complex. Here's a declaration of a function variable
+(analogous to a function pointer in C):
+</p>
+
+<pre>
+f func(func(int,int) int, int) int
+</pre>
+
+<p>
+Or if f returns a function:
+</p>
+
+<pre>
+f func(func(int,int) int, int) func(int, int) int
+</pre>
+
+<p>
+It still reads clearly, from left to right, and it's always obvious
+which name is being declared - the name comes first.
+</p>
+
+<p>
+The distinction between type and expression syntax makes it easy to
+write and invoke closures in Go:
+</p>
+
+<pre>
+sum := func(a, b int) int { return a+b } (3, 4)
+</pre>
+
+<p>
+<b>Pointers</b>
+</p>
+
+<p>
+Pointers are the exception that proves the rule. Notice that in arrays
+and slices, for instance, Go's type syntax puts the brackets on the left
+of the type but the expression syntax puts them on the right of the
+expression:
+</p>
+
+<pre>
+var a []int
+x = a[1]
+</pre>
+
+<p>
+For familiarity, Go's pointers use the * notation from C, but we could
+not bring ourselves to make a similar reversal for pointer types. Thus
+pointers work like this
+</p>
+
+<pre>
+var p *int
+x = *p
+</pre>
+
+<p>
+We couldn't say
+</p>
+
+<pre>
+var p *int
+x = p*
+</pre>
+
+<p>
+because that postfix * would conflate with multiplication. We could have
+used the Pascal ^, for example:
+</p>
+
+<pre>
+var p ^int
+x = p^
+</pre>
+
+<p>
+and perhaps we should have (and chosen another operator for xor),
+because the prefix asterisk on both types and expressions complicates
+things in a number of ways. For instance, although one can write
+</p>
+
+<pre>
+[]int("hi")
+</pre>
+
+<p>
+as a conversion, one must parenthesize the type if it starts with a *:
+</p>
+
+<pre>
+(*int)(nil)
+</pre>
+
+<p>
+Had we been willing to give up * as pointer syntax, those parentheses
+would be unnecessary.
+</p>
+
+<p>
+So Go's pointer syntax is tied to the familiar C form, but those ties
+mean that we cannot break completely from using parentheses to
+disambiguate types and expressions in the grammar.
+</p>
+
+<p>
+Overall, though, we believe Go's type syntax is easier to understand
+than C's, especially when things get complicated.
+</p>
+
+<p>
+<b>Notes</b>
+</p>
+
+<p>
+Go's declarations read left to right. It's been pointed out that C's
+read in a spiral! See <a href="http://c-faq.com/decl/spiral.anderson.html">
+The "Clockwise/Spiral Rule"</a> by David Anderson.
+</p>
diff --git a/doc/docs.html b/doc/docs.html
index 7bdaef9484..4b40bfe4b3 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -103,7 +103,7 @@ Guided tours of Go programs.
<h4>Language</h4>
<ul>
<li><a href="http://blog.golang.org/2010/04/json-rpc-tale-of-interfaces.html">JSON-RPC: a tale of interfaces</a></li>
-<li><a href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">Go's Declaration Syntax</a></li>
+<li><a href="/doc/articles/gos_declaration_syntax.html">Go's Declaration Syntax</a></li>
<li><a href="/doc/articles/defer_panic_recover.html">Defer, Panic, and Recover</a></li>
<li><a href="http://blog.golang.org/2010/09/go-concurrency-patterns-timing-out-and.html">Go Concurrency Patterns: Timing out, moving on</a></li>
<li><a href="/doc/articles/slices_usage_and_internals.html">Go Slices: usage and internals</a></li>
diff --git a/doc/go_faq.html b/doc/go_faq.html
index ce1e178be7..f575410e92 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1524,7 +1524,7 @@ and <code>chan</code> keep things clear.
<p>
See the article about
-<a href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">Go's Declaration Syntax</a>
+<a href="/doc/articles/gos_declaration_syntax.html">Go's Declaration Syntax</a>
for more details.
</p>