by galkk on 1/1/25, 9:03 AM with 75 comments
by palotasb on 1/1/25, 10:06 AM
+----------------------------+
| +-----------------------+ |
| | +------------------+ | |
| | | +-------------+ | | |
| | | | +--------+ | | | |
| | | | | +--+ | | | | |
| | | | | ^ | | | | | |
int * * ¦ ¦ ¦ VAR[1][2][3] | | |
^ | | | | | | | | | | |
| | | | | +-----+ | | | | |
| | | | +----------+ | | | |
| | | +---------------+ | | |
| | ---------------------+ | |
| +-------------------------+ |
+-------------------------------+
The type of VAR is a [1-element] array of [2-element] array of [3-element] array of pointer to pointer to ints. I drew a spiral that passes through each specifier in the correct order. To make the spiral correct it has to skip the pointer specifiers in the first three loops. This is marked by ¦.The Right-Left Rule is quoted less frequently on HN but it's a correct algorithm for deciphering C types: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html
The spiral rule can be modified to process all array specifiers before all pointer specifiers, but then you'd have to specify that the order to do so is right and then left. At that point it's just the Right-Left Rule.
by LysPJ on 1/1/25, 10:29 AM
IMO the Go syntax is a vast improvement as it's much simpler and avoids the clockwise/spiral issue: https://appliedgo.com/blog/go-declaration-syntax
by HexDecOctBin on 1/1/25, 10:14 AM
It was only about 200 lines of code, and yet never have I been happier to finish a solution and never having to think about it again.
by wruza on 1/1/25, 10:00 AM
by fc417fc802 on 1/1/25, 10:07 AM
by f1shy on 1/1/25, 10:43 AM
by sylware on 1/1/25, 12:44 PM
That said, that makes me think of perl5. I though the perl5 coders were doing some kind of sick competition: who is going to use the most implicit code, namely to read the code you would need a complete/perfect/permanent understanding of the full perl5 syntax parser to understand what some code is actually doing. I hate perl5 for that, but ultra complex syntax computer language like c++ and similar (java, rust, etc), are worse. In advanced OOP, you have no idea of what's going on if you don't embrace the full OOP model of a complex program, not to mention it does exponentially increase the syntax complexity, which is a liability in order to get a sane spectrum of alternative "real-life" compilers since those become insane to implement correctly.
If implicit there is in a computer language, it must be very little and very simple, but should be avoided as much as possible. Does it mean more verbose code, well, most of the time yes, and this is usually much better on the long run. For instance in C, I try to avoid complex expression (often I fail, because I am too used to some operators like '++' '--'), many operators should not be around, not pertinent enough (like a ? b : c) only increasing compiler complexity.
by immibis on 1/1/25, 11:42 AM
int p[5] means the type of p[5] is int (but you still have to remember valid elements are 0-4).
void (signal(void()(int))(int) means the type of (signal(something that is a void()(int))(42) is void. And void(p)(int) means the type of (p)(42) is void.
If you can remember the precedence of these operators, you automatically remember the precedence of their "type operators" as well.
by Ferret7446 on 1/4/25, 12:16 PM
If you have int on the left and some kind of declaration for foo on the right, that means that when you use foo with all of the present syntax, you get an int.
For example, in
char *(*fp)( int, float *)
if you use fp like this *(*fp)( int, float *)
you get a char.by casenmgreen on 1/1/25, 11:03 AM
int long long unsigned number_of_days; - read it right to left, an unsigned long long int
float fraction; - read it right to left, "" reads as "pointer to", so pointer to float
by dapperdrake on 1/1/25, 11:07 AM
by alkonaut on 1/1/25, 11:44 AM
by foldr on 1/1/25, 12:53 PM
A lot of people start with the idea that the syntax of C declarations is '<type> <variable_name>'. This works fine for simple cases, but it's completely wrong. What a declaration like 'int x' actually means is the following:
declare a variable x of a type such that the expression x is of type int
In such a simple case this seems unnecessarily long-winded, but now let's look at a more complex case: int (*p[4]) (int x, int y);
declare a variable p of a type such that (*p[i])(x,y) is of type int
If dereferencing the ith element of p and then calling the result with two arguments gives us an int, then p must be an array of pointers to functions that take two arguments and return int. If you saw the expression '(*p[i])(x,y)' in some code, you'd have no difficulty figuring out that p must be an array of function pointers. So you needn't have any difficulty when reading the declaration either.One slightly confusing thing here is that the nesting of the expression syntax is the opposite of the nesting of the type. The expression is
funcall(deref(array_index(p, i)), [x, y])
whereas the type is array_of(pointer_to(function(args: [int, int], returning: int)))
This makes sense once you understand that the expression is to be interpreted just as a normal expression. The first thing you do with an array of something is index into it. So indexation is going to be the most deeply nested part of the expression, even though the outermost layer of the type is 'array of ___'.One additional source of confusion is the '*' operator and the need for additional parentheses in function pointer declarations. In C, function pointers dereference to themselves, so 'p()' and '(*p)()' are equivalent if p is a function pointer. However, in a type declaration you need something to distinguish a function pointer from a function, so the '*' has to be present. Why can't we just write 'int *p[4](int x, int y)' in the example above? Because of how the operator precedence rules work. That expression is equivalent to '*(p[4](x,y))', so it would declare an array of functions returning pointers to integers. (You can't declare an array of functions in C, so that's invalid.)
Ad-hoc rules for interpreting C declarations miss the genius of their underlying concept. You already know all the syntax you need to understand a C type declaration! It's just C expression syntax.
by weinzierl on 1/1/25, 12:08 PM
by pwdisswordfishz on 1/1/25, 9:52 AM
by the_gipsy on 1/1/25, 10:33 AM
by keyle on 1/1/25, 10:51 AM