4 ms·
> And yes, it is possible to support all these things with perfect dynamic memory safety and without increasing pointer size! You had me up to this point. A me
by kbolino 3y ago
> And yes, it is possible to support all these things with perfect dynamic memory safety and without increasing pointer size!
You had me up to this point. A memory-safe union is a discriminated union, which needs extra information (a discriminator) to tell which case is currently active. That doesn't necessarily increase pointer size, but it does break ABI compatibility.
- o11c 3y agoYou don't have to store that in-line, you can store it in metadata. Kind of like how ASAN works, but with typing info instead of just validity info. Now yes, for performance you don't want to do this ... but it can be just one step of the migration.
- kbolino 3y agoIf you're able to accept ABI breakage or changing the C code, then I don't think any major language which is capable of calling C code is missing support for unions. The same cannot be said for varargs, though.
- o11c 3y agoI explicitly refer to untagged unions though, not tagged ones. The lack of a language-known tag is part of the API, not just the ABI. Even library-specific tags should only be considered an incremental upgrade, not the core union support. Yes, it is possible to refactor things like `SDL_Event` to use subclasses instead of unions. But the point is - you shouldn't have to, not at first. And of course, you need to be able to use a union to perform a bitwise cast between float and int. Not some other ad-hoc API; it needs to be trivial to port from C regardless of what the context looks like.
- kbolino 3y agoI'm trying to think of how it would be possible to have memory-safe untagged unions. I don't really think there's a workable solution in the general case, though there might be some specific cases where it works. Undefined behavior is perfectly acceptable for C (though it makes code less portable); it is completely unacceptable in safe languages (outside of unsafe callouts). I'm also not sure why it's necessary to use a union for bitwise conversions. Java and Go, off the top of my head, have safe functions for bitwise int<->float (int32<->float32 in Go) and long<->double (int64<->float64 in Go). Moreover, if I remember correctly, you are only actually allowed to use one case at a time in a C union. If I'm right, then using a union to do bitwise casts is actually undefined behavior in C, even if it almost always works. Put simpler, you cannot write one type into a union then read a different type; you must always read the last type that was written. edit: I dug up my copy of K&R 2/e and yeah, unions are not meant to be used for things like casts. Some supporting text: > A union is a variable that may hold (at different times) objects of different types and sizes, .... (Sec 6.8, p. 147) > Any one of these types may be assigned to u and then used in expressions, so long as the usage is consistent: the type retrieved must be the type most recently stored. It is the programmer's responsibility to keep track of which type is currently stored in a union; the results are implementation-dependent if something is stored as one type and extracted as another. (Sec 6.8, pp. 147-148) In the case of SDL_Event, there actually is a discriminator of sorts. Every case of the union starts with `Uint32 type` and I don't think any case breaks 4-byte alignment on most platforms. With a little compiler support, it would probably be possible to support SDL_Event variables directly in a memory-safe language.