Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: bart Newsgroups: comp.lang.c Subject: Re: do { quit; } else { } Date: Sat, 12 Apr 2025 12:50:07 +0100 Organization: A noiseless patient Spider Lines: 121 Message-ID: References: <20250409142303.00004645@yahoo.com> <87ikndqabc.fsf@nosuchdomain.example.com> <20250410115501.000037a5@yahoo.com> <20250410080629.532@kylheku.com> <87a58mqt2o.fsf@nosuchdomain.example.com> <875xjaqmgf.fsf@nosuchdomain.example.com> <20250411192435.573@kylheku.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Sat, 12 Apr 2025 13:50:07 +0200 (CEST) Injection-Info: dont-email.me; posting-host="5b5cdf67fe25ae40eb3e543c34a3e4c8"; logging-data="463951"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19xJD0RXH/OZXguL2jQCObs" User-Agent: Mozilla Thunderbird Cancel-Lock: sha1:+p7V1SNzyK7P08dcLEOJFpfNRdE= In-Reply-To: <20250411192435.573@kylheku.com> Content-Language: en-GB Bytes: 6046 On 12/04/2025 03:43, Kaz Kylheku wrote: > On 2025-04-12, bart wrote: >> 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! I'm sorry, but it doesn't work! The thought processes are entirely different between writing expressions, and declaring types. They differ in many ways anyway: * A typespec needs a base type; an expr doesn't * A typespec needs to express the whole thing right up to the base type; an expr can be partial * A typespec can include 'const' and other attributes; an expr doesn't * A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref * A typespec uses '[]' for arrays; an expression can choose to use '*' to index * A typespec uses (*) for function pointers, but an expression can choose to omit both that * and the accompanying (). Further if you have an expression like (*A)[i] + (*B[i]) + (*C[i]), then you necessarily have to elaborate each term, but it shouldn't be necessary to repeat that typespec for each in the declarations. C doesn't directly have the means to centralise a common type, you have to do: typedef int (*Arr)[10]; Arr A, B, C; or: typeof(int (*)[10]) A, B, C Here there is a clear (and clean!) disconnect between each variable, and its type. A variable's type shouldn't be something it has to 'wear' wrapped around it, so that it literally looks like an expression. That would be a bizarre concept. But unfortunately people are used to thinking that this is normal: int (*A)[10], (*B[10]), (*C)[10]; Even if you wrote this, perhaps you are passing those pointers to a function: F(A, B, C) Hmm, those terms don't look much like their declarations, do they?! > 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?) Yes, making deref a prefix op was a bad idea. Postfix is much better (but the choice of '*' makes that problematical). My examples become (ignoring the unsuitability of '*'): int A*[10], B*[10], C*[10]; A*[i] + B*[i] + C*[i] Generally cleaner syntax all round. Maybe people would now use proper pointer-to-array types (T(*)[] in current syntax) instead of the less safe T*. The -> operator can be dispensed with too: you write P*.m or Q**.m instead of the messy (*P).m or P->m or (*Q)->m. > 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 I'm lost, sorry. Things are getting more complicated, not simpler!