diff options
Diffstat (limited to 'doc/articles/gos_declaration_syntax.html')
-rw-r--r-- | doc/articles/gos_declaration_syntax.html | 348 |
1 files changed, 0 insertions, 348 deletions
diff --git a/doc/articles/gos_declaration_syntax.html b/doc/articles/gos_declaration_syntax.html deleted file mode 100644 index 455cced1d..000000000 --- a/doc/articles/gos_declaration_syntax.html +++ /dev/null @@ -1,348 +0,0 @@ -<!--{ -"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> |