17 ms·
The author misunderstands some parts of the C language, in particular related to static variables. "In fact, these aren't just file globals accessible to only o
by tom_mellior 8y ago
The author misunderstands some parts of the C language, in particular related to static variables. "In fact, these aren't just file globals accessible to only one translation unit, these are static variables that are accessible across the whole program." gets the meaning of C's static exactly backwards: C file-scope static variables are only accessible (by name) in their translation unit; all other file-scope variables are extern by default.
More importantly, they write:
static struct Lisp_Objfwd o_fwd;
"... creates an (uninitialized) static variable called o_fwd". No. C static variables are implicitly initialized to zero of the appropriate type, in this case, apparently a struct containing only a null pointer. This also means that their
unsafe {
#[allow(const_err)]
static mut o_fwd: ::hacks::Hack<::data::Lisp_Objfwd> =
unsafe { ::hacks::Hack::uninitialized() };
"a lot more typing to get a proper uninitialized value in a Rust program" is just useless voodoo.
- db48x 8y agoYou are entirely correct, and I should perhaps have been more precise. However, because Lisp_Objfwd is basically a pointer, zero-initialized is pretty much as good as uninitialized. It's not a useful value.
- danaliv 8y agoIt fails a NULL check, where an uninitialized value (probably) won’t. That seems like a pretty important distinction, no?
- db48x 8y agoIn C, yes, that's a useful distinction. One of the goals of Rust is that you'll never have to check that manually. You'll never encounter a pointer that points to an invalid, uninitialized, or unallocated object. Since we're writing some unsafe code here, we can operate outside that restriction as long as we promise to put things right before the end of the unsafe block. This can be simplified somewhat once everything is written in Rust.
- beagle3 8y agoThe C spec says zero in a pointer context is null (and the other way around) Can you elaborate on “as good as uninitialized”?
- db48x 8y agoYou can't ever usefully dereference a null pointer, so the only thing you can safely do with it is check to see if it is null. I commented on a sibling comment in more detail, but basically in Rust no reference is allowed to be null except temporarily inside an unsafe context.
- kazinator 8y agoThere isn't anything you can do safely with an actually uninitialized value, though. In the internals of TXR Lisp, I used a null pointer to represent the symbol nil, with all the useful semantics that follows. If an object containing Lisp values is initialized to zero, those values are nil.
- db48x 8y agoYes, Emacs and Remacs do the same thing. All Lisp values are tagged pointers, and a nil gets encoded as a zero value with a zero tag. It's simple and easy to check for, and you won't have any problems as long as you always remember to do so. However, this is not a Lisp value; it's a pointer to one. Specifically, it's a pointer to memory set aside to store a specific Lisp variable's value. Leaving it zeroed makes no sense, because eventually someone is going to store a value in there and it'll have to be allocated anyway. Better to do that all in one large block, rather than a thousand tiny ones. Even if we wanted to lazily allocate these, we can't leave a simple Rust reference (or pointer) null past the end of the unsafe block. Rust does have an Option type, and if you use it on a type that isn't nullable, then the compiler will use the zero value for None variant and all other values for the Some. Since references can never be null, an Option<&T> will always take up the same amount of space as a &T; there's no additional overhead. At some point, when enough of the C code is ported to Rust, I'm sure we'll start using this to represent all Lisp values and a Lisp nil will always be a Rust None.
- kazinator 8y ago> gets the meaning of C's static exactly backwards Which one? It has multiple. First, there is storage duration: C99 6.2.4 "There are three storage durations: static, automatic, and allocated." Variables with external linkage defined at file scope are static in the sense that they have static storage duration; it is not incorrect to call them static variables, though a bit unusual. If they have external linkage, it's more common just to call them globals. The static storage class specifier keyword used at file scope causes a name to have internal linkage. In a block scope, it requests the above static storage duration.
- tom_mellior 8y ago> Which one? The one that was entirely clear from context: Linkage.