places, or what is up with `*x` not always meaning the same thing in different contexts
but there are operations in the language that expect a
place(T), and therefore do not perform the implicit conversion.2024-05-18 one of these operations is assignment, which is like a function
place(T) -> T -> T.it accepts a
place(T)to write to, aTto write to that place, and returns theTwritten. note that in that case no read occurs, since the implicit conversion described before does not apply.void example(void) { int x = 0; x /*: place(int) */ = 1 /*: int */; /*-> int (discarded) */ }2024-05-18 another couple of operations that accept a
place(T)is the.and[]operators, both of which can be used to refer to subplaces within the place.2024-05-18 the
[]operator takes in aT*, aptrdiff_tto offset the pointer by, and returns aplace(T)whose memory location is the offset pointer. the function signature is thereforeT* -> ptrdiff_t -> place(T).example:
void example(int* array) { int* p = &((array /*: int* */)[123] /*: place(int) */); }2024-05-18
now I have to confess, I lied to you. there are no places in C.
2024-05-18 the C standard actually calls this concept “lvalues”, which comes from the fact that they are values which are valid left-hand sides of assignment.
2024-05-18 however, I don’t like that name since it’s quite esoteric - if you tell a beginner “
xis not an lvalue,” they will look at you confused. but if you tell a beginner “xis not a place in memory,” then it’s immediately more clear!so I will keep using the Rust name despite the name “lvalues” technically being more “correct” and standards-compliant.
2024-05-18
what’s interesting about
place(T)is that it’s actually a real type in C++ - except under a different name:T&.2024-05-18 to begin with, in C we could assume that referencing any variable
T xby its namexwould produce aplace(T). this is a simple and clear rule to understand.2024-05-18 in C++, this is no longer the case - referencing a variable
T xby its namexproduces aT&, but referencing a variableT& xby its namexproduces aT&, not aT& &!in layman’s terms, C++ makes it impossible to rebind references to something else. you can’t make this variable point to
y:int x = 0; int y = 1; int& r = x; r = y; // nope, this is just the same as x = y2024-05-18
anyways, as a final
bossbonus of this blog post, I’d like to introduce you to thex->yoperator (the C one)2024-05-18 if you’ve been programmming C or C++ for a while, you’ll know that it’s pretty dangerous to just go pointer-walkin’ with the
->operatorint* third(struct list* first) { return &list->next->next->value; }2024-05-18 the conclusion here is that chaining
x->ycan be really dangerous if you don’t check for the validity of each reference. just doing one hop and a reference -&x->y- is fine, because we never end up reading from the invalid pointer - it’s like doing&x[1]. but two hops is where it gets hairy - inx->y->z, the->zhas to read fromx->yto know the pointer to read from.2024-05-18
