5 ms·
Can you elaborate? My point is that the concepts "having a datatype, that stores an address" and "reading (typed) data stored at a specific address" are differ
by protomikron 10y ago
Can you elaborate?
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.
- belovedeagle 10y agoI don't see how the bool example follows; in what way is negating a boolean like dereferencing a pointer w/r/t types? ! is bool->bool; * is * P -> P. 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 int
- protomikron 10y agoYeah, sorry, my example sucks. However, I am still believing a different operator would make more sense.
- belovedeagle 10y agoAnd what of [a-zA-Z0-9_]? Why should we allow them in both types and variables and functions? That's really confusing.
- munificent 10y ago> My point is that the concepts "having a datatype, that stores an address" and "reading (typed) data stored at a specific address" 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.
- protomikron 10y agoWow this is really interesting, I did not know that, and it explains their choices. And C's function pointer types are indeed written in a bizarre way. I definitely think of (int * i) as (i :: Ptr Integer) and (* i) in an expression like 42 + * i as (* :: Ptr Integer -> Integer).
- evincarofautumn 10y agoYeah, as long as we’re mixing notations, it’s really: *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.
- yarou 10y ago> In practice, it turns out that composed types don't seem to be that hard. 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.
- munificent 10y agoI'm not talking about higher-kinded types, just type annotations that are more than just a single bare identifier. Stuff like: List<int> (Some, Tuple, Type) Matrix[4][4] (Para, Meter) -> ReturnType
- roel_v 10y agoI'm probably misunderstanding you, but can I rephrase your comment as saying 'int i is the natural way of declaring a pointer to an int, and not int i'? Because if so, I don't recall that from the K&R (and I've read it front to back several times, not that that means much - I can't even remember if they use int* i or int *i, and I don't have my copy at hand here).
- emmelaich 10y agoMy elaboration is a bit late ... but. int i, *p; Tells me that i is an int. And so is *p.
- metaphor 10y agoThis had a way of always confusing me. For clarity, I'd declare them as: int i; int* p;
- mfukar 10y agoThink of it from the perspective of types: int *p; /* What is the type of p? Pointer to int */ int a = *p; /* What is the type of *p? int */