Rust supports inline assembly [and therefore there's no guarantee that the "type" was set correctly when any member of the union was set], and the lock part of its standard library should be trivially portable to or reimplemented in a freestanding environment [which is entirely irrelevant for me given that there is no libraries at all and therefore no difference between hosted and freestanding]. There's no reason you couldn't use structures/unions in block-free code either [except that you'd have to atomically write both the union member and the "type" at the same time, which is simply not possible in most cases]. A lock is only required if the variable is mutable and shared between threads (actually this is enforced by the type signatures of the library functions for threads [which means it's not enforced at all because anyone can write their own alternatives to the library functions instead]).Rusky wrote:Rust supports inline assembly, and the lock part of its standard library should be trivially portable to or reimplemented in a freestanding environment. There's no reason you couldn't use structures/unions in block-free code either. A lock is only required if the variable is mutable and shared between threads (actually this is enforced by the type signatures of the library functions for threads).Brendan wrote:I need to support assembly language or it'd be useless; and there won't be any standard library (or any standard library lock implementation). I'd also want to ensure that its possible to use structure/union members in block-free code.
So you're suggesting that, given that I will not bother with unions at all, I should also not bother trying to co-locate structure members?Rusky wrote:The main reasons for using unions are generally not the trivial case, and I suspect they are not the possible cases either. The main reasons for unions always use tags anyway (or they're bitcasting, which you can do other ways). Thus, trying to auto-detect potentially overlapping members in structs is probably not worth it.Brendan wrote:Given the choice between failing to co-locate structure members when it is possible, and making programmers learn and use an extra union thing plus an explicit tag; then the former is the "least worst" alternative.
For co-locating structure members; the halting problem is a broken anology. It assumes that I must have a correct decision (no "false positives" and no "false negatives") and this is a very wrong assumption. I do need "no false positives", because this leads to co-locating structure members that shouldn't be co-located (a compiler that automatically inserts bugs into perfect source code). However; I do not need "no false negatives" because this only means a missed opportunity for optimisation. If I only co-locate structure members when it's trivial to prove that it's safe, then that's good enough (but obviously "better" would be better).
The only real question here is; how much better than "only when trivial" is possible?
As far as a programmer should care, that's functionally identical to structure with a "type" field and a "switch(something->type) {". Why do you think programmers using a high level language should need to do explicit micro-optimisations by hand? A programmer shouldn't have to think about all of the potential use cases of their data structure before being forced to decide whether to use a structure or union.Rusky wrote:The alternative, enforcing safe tagged unions, is not really anything new (although I would ask, why is giving programmers a new tool a bad thing per se?). Not only that, it enables several useful patterns that are otherwise either unenforceable or overly verbose. In Rust, it looks like this:It is accessed like this:Code: Select all
enum Shape { Circle { center: Point, radius: f64 }, Rectangle { top_left: Point, bottom_right: Point } }
Code: Select all
match shape { Circle { radius: radius, .. } => f64::consts::PI * square(radius), Rectangle { top_left: top_left, bottom_right: bottom_right } => { (bottom_right.x - top_left.x) * (top_left.y - bottom_right.y) } }
What happens in 3 years time when the programmer that decided to use your unions realises that they need to add a "type = both_circle_and_rectangle" to the enum? Do they have to find all of the existing code that does anything with the old union and rewrite all of it so it works for structures instead before they can start thinking about adding any new code for the "both_circle_and_rectangle" case?
If it allows assembly then pointers can be null. Of course null is only one of a very large number of invalid values that a pointer could contain; so caring about null and not caring about all of the other invalid values is relatively short-sighted.Rusky wrote:One example of a new feature (that's been mentioned before in this thread) is null safety using Option types. In Rust, pointers cannot be null. Thus, if you need to store a nullable pointer, you wrap the usual pointer type in a union:
Cheers,
Brendan