Which the declaration syntax hints at:
int i, *p;Which the declaration syntax hints at:
int i, *p;My point is that the concepts "having a datatype, that stores an address" and "reading (typed) data stored at a specific address" are different, but share the same keyword (which is in this case just one symbol - maybe because C programmers have to use it often).
E.g. assuming C99's bool (0|1) datatype, you might define the "negate" functionality, which is often done by '!'. So we have something like that:
// init a new bool
bool success = 1;
...
// negate the bool
if (!success) {
...
}
For me that makes sense. However if we take the pointer approach (as it is implemented), it would look like this: // init a new bool
bool success = 1;
...
// negate the bool
if (bool success) {
...
}
I hope this makes sense. For an experienced programmer * 's role is obvious from the context, but for me that was the most troubling concept when starting with C's pointers.The reason the same symbol is used is because of the way C types are read:
int x; // (x) is an int
int *x; // (*x) is an int
int **x; // (**x) is an int
int x(double); // (x(1.)) is an intHowever, I am still believing a different operator would make more sense.
They are different things, but C's syntax was deliberately designed to imply the former from the latter. "Declaration reflects use" is the term they used for it.
The idea is that in something like:
int *i;
You don't read it like, "Declare a variable 'i' whose type is 'int star', which is a pointer to an int". You read it like "declare variable 'i' whose type is such that taking 'star i' (i.e. doing a dereference) would give you an int". The type in this case is a pointer to an int.This is always why function pointer syntax is so totally bizarre in C.
"Declaration reflects use" was a neat idea, but I think it practice it ended up causing more confusion than it solved. At the time, maybe they thought users would be tripped up by compound type expressions and thought it would help if they focused on the operations performed on the variable being declared.
In practice, it turns out that composed types don't seem to be that hard.
I definitely think of (int * i) as (i :: Ptr Integer) and (* i) in an expression like 42 + * i as (* :: Ptr Integer -> Integer).
*i :: Integer
From which you can conclude i :: Ptr Integer.And the dereference operator does have the type you specified, but not in an lvalue—there the operator is really a mixfix one:
(*_ = _) :: Ptr a -> a -> a
This isn’t specified directly by the standard, but follows from the rules about how an assignment operator must examine the structure of its first operand.Depends on what you mean by hard. Hard to read or hard to reason about?
* -> * and * -> * -> * are easy to read and reason about, i.e. Int -> Char -> Int. But what about types of types?
(* -> * ) -> * is confusing to reason about IMO. i.e. Applicative Functors:
(<$>) :: Functor f => (a -> b) -> f a -> f b
Not really intuitive at all, the only reason I can understand it is that I know what functors and Monads are.
List<int>
(Some, Tuple, Type)
Matrix[4][4]
(Para, Meter) -> ReturnType> I don't recall that from the K&R
I don't recall either, but this Wikipedia mention of "declaration reflects use" cites K&R:
https://en.wikipedia.org/wiki/C_%28programming_language%29#C...
Yes I agree about the 'declaration reflects use'; what I meant was: does that imply that the declaration should consider the asterisk (the 'make this a pointer' part) to be 'part of', and thus right next to, the variable name or the type?
I'm strongly in the 'type' camp myself, and therefore I think that int *p; is nonsense; only to be used out of necessity when declaring multiple pointer variables on one line. So I'm wondering if 'declaration reflects use' reaffirms that, or contradicts it.
int i, *p;
Tells me that i is an int. And so is *p. int i;
int* p; int *p; /* What is the type of p? Pointer to int */
int a = *p; /* What is the type of *p? int */