3 ms·
I find your comment inflammatory and your zealousness amusing, but I'll bite and try to be reasonable by assuming you're willing to entertain another point of v
by optymizer 6y ago
I find your comment inflammatory and your zealousness amusing, but I'll bite and try to be reasonable by assuming you're willing to entertain another point of view.
The whole "declaration follows usage" is just a bad tradeoff. It makes it easier to parse expressions. That's my understanding of why they did it. It makes it _objectively_ harder to read, because some declarations follow this easy pattern of "name on the right and type on the left", while for some other declarations you have to employ the spiral reading pattern (e.g. for function pointers, arrays, with variable declarations being the easiest one).
You know what's easier that all that? Type on the left, name on the right.
int a;
int* a;
int[] a;
unsigned int(int) f;
Notice that you can probably easily guess what that last declaration represents, without having to consult a wise old man. I think you simply got used to how C does it, so now the actual sane way is weird to you personally, but you have to recognize that it's one additional thing _everyone_ has to learn because it's counter-intuitive. Hundreds of thousands of developers had to learn some weird spiral reading rule because 1 compiler writer found it easier to reuse a yacc rule.
That's why Java, Go and D changed this nonsense. Java supports both "int[] a" vs "int a[]". They support both to appease everyone, but they went the extra mile to support "int[] a". D changed it to "int[] a" and called it a day and Go introduced this novel [5]int syntax, which is different, but clearly easy to read ("array of five int").
Again, type on the left, name on the right (or in Go's case, name on the left, type on the right - but at least it's not a mixed bag). Once you see it that way (i.e. you give up on declaration follows usage rule), it's not weird, it's not wrong, it's intuitive, and it makes the language easier to learn and use.
I thought this is a matter of preference until I actually wrote a C compiler for fun and have permanently solidified my opinion on this issue.
The asterisk is part of the type, it's not just some random symbol, it's not a type qualifier like 'const' or 'volatile'. It's a type token that builds a distinct type, e.g. "int * * " is a type that spells "pointer to pointer to int", it's not an 'int' type with some flags attached to it.
Let's take the concrete example of 'struct Bark* p_dog'.
A typical compiler will tokenize 'struct', 'Bark', '* ' and 'p_dog' and will group them as ('struct', 'Bark', '* ') to derive the type "pointer to struct Bark" and ('p_dog') to derive the name of the symbol when it adds an entry into its symbol table, in other words - the compiler itself splits that line so that types are the left, and names on the right.
- bigdict 6y agoAgree 100%. It is a tradeoff that detracts from ease of human interpretation. Because C makes that tradeoff, int *a; is idiomatic C and int* a; isn't. For C programming to be pleasant, you have to understand and agree with the philosophy at least while you're writing C. Go developers changed this in a particularly elegant way. Here's what Rob Pike has to say: https://blog.golang.org/declaration-syntax https://blog.golang.org/declaration-syntax. I too gained a better understanding of the problem after going through a compiler-writing exercise.
- rootbear 6y agoIt wasn't my intention to be inflammatory and I don't consider myself a zealot. My comment has generated a lot of interesting discussion and that's a good thing, and probably worth the down votes. I wrote C for a long time before I ever even heard of the spiral rule. I do think that the "declaration follows usage" idea worked a lot better before C declarations became so complex. I'm not claiming that the C declaration syntax is wonderful, it isn't. I just think that the C++ style of pretending that int* is a pointer type is misleading, since that's not really what's happening grammatically. Yes, * is a type token, as you say, but it modifies the identifier, not the type specifier. But since the style now is to only declare one variable per declaration, and to always initialize it, then in practice it isn't actually all that confusing. I have always wanted to write a compiler and I'm sure I would get a new perspective on these matters if I did. Go has done a lot to clean up C's messes. I haven't used it much, but I'd like to know it better.