On 2025-04-12, bart <
bc@freeuk.com> wrote:
On 12/04/2025 00:59, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a "nightmare".
>
Annoying would be having to get letter case or punctuation just right.
[...]
So, yeah, a 'nightmare' is more apt than 'annoying'.
Bart, bart, bart.
>
>
You made a false statement about how *everyone* feels about
C's declaration syntax.
>
So what would be a true statement? That everyone finds it at least midly
annoying?
>
C type syntax is famous for being difficult and confusing; I think most
will agree about that. Even the creators said so.
If you had a function that takes an int, that returned a pointer to an
array, how would you pass in 42, and then get at the third element?
f(42) // gets the pointer to the array
(*f(42)) // designates the array
(*f(42))[2] // gets at the third element.
Ok, now declaring a function of int, which returns a pointer to an array
of 16 elements:
(*f(int))[16];
Notice any resemblance? The 42 argumet has changed to a type specifier
for the corresponding parameter type. The array reference turns into
the size. Minor!
We need a type specifier to the elements:
double (*f(int))[16];
Declaration follows use: it's not just a slogan, it's real!
If you don't like the declaration syntax, it's possibly because
you don't like the expression syntax for working with pointer
dereferencing and arrays, which it mirrors. (You not liking
C expression syntax: billion to one odds, right?)
Making the type operators in the declarator resemble the unary
and postfix operators of the use is kind of clever though!
IDEA: maybe you would like the "dedclaration follows use", if it was
rendered over a different expression grammar in which pointer, arrays
and whatnot work the way you like. If didn't dislike the "use",
you might not dislike "declaration follows use".
Now, from this "envelope shape":
double (.......)[16];
we know that whatever ..... is, it is an array of 16 doubles.
This .... is called a "type hole" by functional programmers working
in Haskell and whatnot.
If we replace the hole with a name like abc:
double (abc)[16];
then what is being declared is that name. We get an object abc which is
such an array. The parentheses are then unnecessary and we can drop
them.
If we plug in *f(int) instead of abc, then *f(int) isn't what is
being declared: f is. But we know that when this f is called, and the
pointer it returns is dereferenced, we get an array. We know that from
its correspondence to the ..... hole in the expression. Thus the
function mut be returning a pointer to an array (of 16 double).
The parentheses remain necessary then because the * on the left
has lower precedence than the postfixes (int) and [16].
There is kind of minor algebra to it all, where you can
play these substitution games.
The declarator type constructors like the (...) function
parentheses, [...] array brackets and the prefix * pointer are not
called operators in ISO C, but they mimic the unary and postfix
operators and have the same associativity and precedence. Moreover, the
parentheses function the same way, for overriding precedence.
If you know that postfix binds tighter than unary, but parentheses
override, that's 90% of it.
-- TXR Programming Language: http://nongnu.org/txrCygnal: Cygwin Native Application Library: http://kylheku.com/cygnalMastodon: @Kazinator@mstdn.ca