github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/gos-declaration-syntax.article (about)

     1  Go's Declaration Syntax
     2  7 Jul 2010
     3  Tags: c, syntax, ethos
     4  
     5  Rob Pike
     6  
     7  * Introduction
     8  
     9  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.
    10  
    11  * C syntax
    12  
    13  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
    14  
    15  	int x;
    16  
    17  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.
    18  
    19  Thus, the declarations
    20  
    21  	int *p;
    22  	int a[3];
    23  
    24  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.
    25  
    26  What about functions? Originally, C's function declarations wrote the types of the arguments outside the parens, like this:
    27  
    28  	int main(argc, argv)
    29  	    int argc;
    30  	    char *argv[];
    31  	{ /* ... */ }
    32  
    33  Again, we see that main is a function because the expression main(argc, argv) returns an int. In modern notation we'd write
    34  
    35  	int main(int argc, char *argv[]) { /* ... */ }
    36  
    37  but the basic structure is the same.
    38  
    39  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:
    40  
    41  	int (*fp)(int a, int b);
    42  
    43  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?
    44  
    45  	int (*fp)(int (*ff)(int x, int y), int b)
    46  
    47  That's starting to get hard to read.
    48  
    49  Of course, we can leave out the name of the parameters when we declare a function, so main can be declared
    50  
    51  	int main(int, char *[])
    52  
    53  Recall that argv is declared like this,
    54  
    55  	char *argv[]
    56  
    57  so you drop the name from the middle 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.
    58  
    59  And look what happens to fp's declaration if you don't name the parameters:
    60  
    61  	int (*fp)(int (*)(int, int), int)
    62  
    63  Not only is it not obvious where to put the name inside
    64  
    65  	int (*)(int, int)
    66  
    67  it's not exactly clear that it's a function pointer declaration at all. And what if the return type is a function pointer?
    68  
    69  	int (*(*fp)(int (*)(int, int), int))(int, int)
    70  
    71  It's hard even to see that this declaration is about fp.
    72  
    73  You can construct more elaborate examples but these should illustrate some of the difficulties that C's declaration syntax can introduce.
    74  
    75  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
    76  
    77  	(int)M_PI
    78  
    79  * Go syntax
    80  
    81  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)
    82  
    83  	x: int
    84  	p: pointer to int
    85  	a: array[3] of int
    86  
    87  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:
    88  
    89  	x int
    90  	p *int
    91  	a [3]int
    92  
    93  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.
    94  
    95  Now consider functions. Let's transcribe the declaration for main as it would read in Go, although the real main function in Go takes no arguments:
    96  
    97  	func main(argc int, argv []string) int
    98  
    99  Superficially that's not much different from C, other than the change from `char` arrays to strings, but it reads well from left to right:
   100  
   101  function main takes an int and a slice of strings and returns an int.
   102  
   103  Drop the parameter names and it's just as clear - they're always first so there's no confusion.
   104  
   105  	func main(int, []string) int
   106  
   107  One merit 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):
   108  
   109  	f func(func(int,int) int, int) int
   110  
   111  Or if f returns a function:
   112  
   113  	f func(func(int,int) int, int) func(int, int) int
   114  
   115  It still reads clearly, from left to right, and it's always obvious which name is being declared - the name comes first.
   116  
   117  The distinction between type and expression syntax makes it easy to write and invoke closures in Go:
   118  
   119  	sum := func(a, b int) int { return a+b } (3, 4)
   120  
   121  * Pointers
   122  
   123  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:
   124  
   125  	var a []int
   126  	x = a[1]
   127  
   128  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
   129  
   130  	var p *int
   131  	x = *p
   132  
   133  We couldn't say
   134  
   135  	var p *int
   136  	x = p*
   137  
   138  because that postfix * would conflate with multiplication. We could have used the Pascal ^, for example:
   139  
   140  	var p ^int
   141  	x = p^
   142  
   143  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
   144  
   145  	[]int("hi")
   146  
   147  as a conversion, one must parenthesize the type if it starts with a *:
   148  
   149  	(*int)(nil)
   150  
   151  Had we been willing to give up * as pointer syntax, those parentheses would be unnecessary.
   152  
   153  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.
   154  
   155  Overall, though, we believe Go's type syntax is easier to understand than C's, especially when things get complicated.
   156  
   157  * Notes
   158  
   159  Go's declarations read left to right. It's been pointed out that C's read in a spiral! See [[http://c-faq.com/decl/spiral.anderson.html][ The "Clockwise/Spiral Rule"]] by David Anderson.