4 ms·
Yeah but this quickly breaks down -- it's not how it "really works". What about arrays for example? int* x[200]; You can fight all you want, but C doesn't
by jstimpfle 2y ago
Yeah but this quickly breaks down -- it's not how it "really works". What about arrays for example?
int* x[200];
You can fight all you want, but C doesn't have type syntax. What you're looking at is expression syntax.
- nuancebydefault 2y agoI would read that x is a collection of 200 intPointers. Is that not correct?
- jstimpfle 2y agoWell yes but there is something off because 200 is not with the "type" anymore. Now do a pointer to an array of 200 ints.
- nuancebydefault 2y agoOh, now i think i know what you mean. 'a is of type one hundred intPointers' should, to be more consistent, be written as (int*)[100] a; I'm not even sure whether that works, never tried it. The fact that arrays are automatically pointers is very confusing for beginners, especially multi dimension arrays are brainbenders in that respect.
- teo_zero 2y agoOf course you can read it. That was just an example to show that C declarations can't always be decomposed into a left part which is the type and a right one which is the variable. It works on the simple case of a pointer, because * is a prefix operator, but it fails on arrays, because [] is postfix. int * <---> foo; int [] <---> foo; // ugh no! The latter would work if C had been designed differently, with operations defined on types. But it was designed with operations defined on values, not on types. There's not a way to express "foo is a pointer to int", you must say "when you dereference foo you get an int" (in fact, * means dereference, not pointer). Imagine if English had not a word for "son". To say Bob is Adam's son you would say "Bob's father is Adam". To tell the truth, C does have the dual of * that is &. If operations on types were defined (and they are not!), then we could have a syntax like this: &int foo; In any case, we wouldn't solve the issue with arrays, because, while [] is the operator that, given an array, returns one element of it, its inverse operator doesn't exist. It's not difficult to imagine a different language with a rich set of operators defined for types. We could have &T for "pointer to type T", Tn (note the infix , as multiplication) for "array of n elements of type T", and so on. Then declarations could be easier: &int ptr; float*3 rgb; &int*8 foo; // array of 8 ptr &(int*8) bar; // ptr to array See how we are using full expressions including parentheses with types? At this point, you would also move the variable to the left and the type to the right, and maybe add a colon for clarity: ptr : ∫ rgb : float * 3; foo : &int * 8; bar : &(int * 8); But this is another language, not C.
- knome 2y ago>foo : &int * 8; >bar : &(int * 8); while just about anything is better than the original, we could certainly do better. I am curious how you expected to handle function pointer syntax, as that is the usual bear of C typing. let's aim to make the types unambiguous, simple to read and write all C types can take at most one parameterizing type, so prefixing works unambiguously. force const and volatile to be exclusively prefixing as well, sorting the weirdness trailing consts would allow. () can represent a function-pointer, with its return type following your examples would be ptr : *int rgb : [3]float foo : [8]*int bar : *[8]int that would leave complex : a [](int, int)**(int,int)*const*volatile*(int,int)[][]*[][16]*char ; vs char *(*(* volatile * const (**a[](int , int ))(int , int ))(int , int )[][])[][16] I couldn't have written that second one without https://cdecl.org/ https://cdecl.org/ Of course, this simple prefixing is also exactly what Go did to improve the types, with some syntactic sugar to help the reader along.
- teo_zero 2y agoOh yes, introducing expressions on types means defining a new, specific syntax for each construct. However, I strongly believe well-known symbols should keep their properties independently of whether they are used in type expression or in value expressions. So, for example, [] is already a postfix operator: it would be confusing if it was sometimes a postfix sometimes a prefix. And the unary * is already used to dereference, it would be weird if sometimes it was used to take a reference instead (for that there's already the unary &). And don't forget the precedence: you shouldn't redefine it. So &int[] would mean &(int[]) not (&int)[]. And since we're talking of a hypothetical new language, for function types I'd choose to re-use an existing operator although for a completely different meaning: ->