Once I saw another article on Habré, dedicated to a completely new and unexplored Go language for me, I decided to try what kind of animal it was and what it was eaten with
(Mostly, of course, I liked the logo) . Of course, the language has many features and is quite convenient. But what immediately surprised me was the principle of variable declaration, which is different from C-like languages, namely, the type of variables is described to the right of the variable name. As a person who practically grew up in C, I was surprised. Then of course I remembered Pascal that there, too, the type of the variable was on the right. Being interested in this question, I tried to understand why one or another syntax for describing the type of variables in these 2 languages is used.

We begin with a description of the syntax for declaring variables in C-like languages. In C, it was decided to abandon a separate syntax for describing variables and allow variables to be declared as expressions:
int x;
As we can see, the type of the variable is on the left, then the name of the variable. Due to this, we maximally bring the declaration of the variable to the usual expression. Suppose this:
')
int x = 5;
Or this:
int x = y*z;
In principle, everything is simple and clear, and quite logical, let's look at the definition of functions in C.
Initially, C used the following function definition syntax:
int main(argc, argv) int argc; char *argv[]; { }
Variable types were not described together with the names of the arguments, but then the syntax was replaced with another one:
int main(int argc, char *argv[]) { }
Everything here is also quite simple and understandable. But this convenience begins to evaporate when pointers to functions and functions that can take pointers to them come into play.
int (*fp)(int a, int b)
Here fp is a reference to a function that takes 2 arguments and returns an int. In principle, it is not difficult, but what will happen if one of the arguments is a function reference:
int (*fp)(int (*ff)(int x, int y), int b)
Already somehow complicated or here is an example:
int (*(*fp)(int (*)(int, int), int))(int, int)
In it, to be honest, I got lost.
As can be seen from the description, when declaring function pointers in C languages, there is a significant drawback in the readability of the code. Now let's look at what method suggests using the variable definitions in C by David Anderson. Reading takes place according to the Clockwise / Spiral Rule method (clockwise / spiral).
This method has 3 rules:
- Reading begins with an unknown element in a spiral motion;
- Spiral expression processing continues until all characters are covered;
- Reading must begin with parentheses.
Example 1:

Following the rule, we start with an unknown str:
- Moving in a spiral, the first thing we see is the symbol '['. So we are dealing with an array
- str array of 10 elements;
- We continue the movement in a spiral and the next symbol is '*'. So this is a pointer.
- str array of 10 pointers;
- Continuing the movement in a spiral, we arrive at the symbol ';', meaning the end of the expression. Spiraling and finding the char data type
- str array of 10 pointers to type char.
Take an example more complicated
Example 2:

- The first unknown that we see is signal. We start the movement in a spiral from it and see the bracket. It means that:
- signal is a function that accepts int and ...
- Here we see the second unknown and try to analyze it. By the same rule we move from it in a spiral and see that it is a pointer.
- fp pointer to ...
- We continue the movement and see the symbol '('. Means:
- fp is a pointer to a function that takes an int and returns ...
- Spiral and see 'void'. It follows that:
- fp is a pointer to a function that accepts an int and returns nothing;
- The fp analysis is complete and we return to signal
- signal is a function that accepts an int and a pointer to a function, which accepts an int and does not return anything;
- Continuing the movement we see the symbol '*', which means
- signal is a function that accepts an int and a pointer to a function, accepts an int and returns nothing, and returns a pointer to ...
- Spiraling and we see '(', which means
- signal is a function that accepts an int and a pointer to a function, accepts an int and does not return anything, and returns a pointer to a function that accepts an int ...
- Make the last round and get the following
- signal is a function that accepts an int and a pointer to a function, accepts an int and does not return anything, and returns a pointer to a function, accepts an int and returns a void.
So, without much effort, David Anderson suggests that we read the definition of variables.
Now let's look at the diametrically opposite syntax when the type of a variable is to the right of the variable name, using the example of Go.
In Go, variables are read from left to right and look like this:
var x int var p *int var a [3]int
There is no need to use any spiral methods, it is read simply
- the variable
a is an array consisting of 3 elements of type int.
With functions, too, everything is quite simple:
func main(argc int, argv []string) int
And this announcement is also read with ease from left to right.
Even complex functions that accept other functions are readable from left to right:
f func(func(int,int) int, int) int
f is a function that takes a function, which, in turn, takes 2 integers in parameters and returns an integer, and an integer, and returns an integer.
These are the differences in the definition of variables in the languages of the C and Go family. Obviously, Go clearly wins this. But if we now recall which languages grew out of the good old C - this is C ++, C #, Java - they all use the definition of variables of this type. And they are built on OOP paradigms and do not use (or practically do not use) the transfer of pointers to functions, all of which have been replaced by classes for us. The drawbacks that come to light on the definition of the type of variable on the left evaporate when using OOP.