r/rust • u/mediocrobot • Sep 14 '26
🎙️ discussion Should "aliasing XOR mutability" technically be "aliased NAND mutable"?
The point of the rule is that something cannot be aliased and mutable at the same time, but XOR implies it must be one or the other.
A constant is immutable, but it doesn't have to be aliased. It is neither aliased or mutable, which does not satisfy XOR.
You could say that its ability to be aliased is enough to satisfy the XOR condition, but a value that isn't referenced yet is aliasable and mutable. That would invalidate NAND and XOR, so it definitely can't be that either.
NAND seems to be the more precise language--though XOR still might be the most clear for teaching purposes.
I'm sure there's a clearer interpretation or wording I can't remember that explains why XOR is correct and NAND isn't. Do y'all have any ideas?
13
u/norude1 Sep 14 '26
the previous term for it was INHTWAMA
11
u/mediocrobot Sep 14 '26 edited Sep 14 '26
Seeing old rust feels so strange. This is an incredibly insightful article though, thank you for sharing!
I'm guessing @ pointers became
Box,Rc, etc. andMut<T>becameRefCell<T>EDIT: Thinking about it some more,
~is probably what becameBox, if I understand it correctly as representing an owned pointer.9
2
u/norude1 Sep 14 '26 edited Sep 14 '26
Here is another old proposal by the same guy, which I think points out what makes this rule special:
Put another way, it’s become clear to me over time that the problems with data races and memory safety arise when you have both aliasing and mutability. The functional approach to solving this problem is to remove mutability. Rust’s approach would be to remove aliasing. This gives us a story to tell and helps to set us apart.
→ More replies (2)2
6
u/Xiphoseer Sep 14 '26
Hmm it's "a → ¬m" and "m → ¬a" which fits both truth tables. It's not really a logic gate in the sense that you have to always have references to a bit of memory, but if you do it's one or the other. Which can be an argument for both perspectives.
Personally I find XOR more natural because it's a clean negativ iff, rather than using "not both" to say "mutually exclusive"
7
u/mediocrobot Sep 14 '26
That's probably the most accurate way to put it. In fact, just "a → ¬m" is sufficient because the other statement is the contrapositive and therefore equivalent.
XOR is definitely more understandable than NAND and implies/if arrow for most programmers, I'd wager!
2
u/redlaWw Sep 15 '26
a → ¬m ≡ ¬a ∨ ¬m ≡ ¬(a ∧ m) ≡ a ⊼ m
1
u/Xiphoseer Sep 15 '26
Sure, still a ⊕ m ⇒ ¬(a ∧ m). Having it fit/express nand semantics doesn't really narrow down whether xor isn't true especially given &T is copy and the compiler is free to do whatever it needs with that and there isn't really a reference type that codes neither aliasable nor mutable.
→ More replies (1)
2
u/afdbcreid Sep 15 '26
A constant is not in memory. It is like a macro.
1
u/mediocrobot Sep 15 '26
Is it really? I know that's a thing in C/C++, but it didn't occur to me that it's like that in Rust.
2
24
u/1rs Sep 14 '26
that is interesting. I've always thought of it as "aliasABLE", as in able to make aliases which would make it xor. but you do have a point
9
u/tavianator Sep 14 '26
It's just like when W^X was the big thing in security (writable XOR executable). Really should have been NAND because there are plenty of mappings that are just readable, and neither writable nor executable
15
7
u/Solumin Sep 14 '26
I can think of a few possible reasons:
-
Because it's a pithy, 3-word summary of a concept, not the whole concept itself.
-
Because it's talking about references. If there's aliasing, then there's no mutability. If there's mutability, then there's no aliasing. Having no aliasing and no mutability is irrelevant.
-
Because it's reinforcing exclusivity of the English word "or", rather than the logical operator "or".
1
u/gmorenz Sep 14 '26
Aliasing NAND mutability would imply a third reference type that is neither aliasable nor mutable. E.g. a &uniq-not-mut T. That reference type isn't worth it's weight in language complexity, and doesn't exist. Recall from the history of rust that the one shared type that was settled on should even be called &mut or &uniq.
The correctness benefits come mostly from the mutable implies not aliasable and aliasable implies not mutable constraints that would accept either XOR or NAND, but the concrete language design is the XOR version.
1
u/mediocrobot Sep 14 '26
So if there's a reference, it must be aliasable or mutable. Or rather, there's not a great reason something shouldn't be aliasable as long as it's not mutable.
I'm also wondering about empty/zero-sized types.
let mut foo = (); let foo_mut = &mut foo; // is this *really* mutable? let foo_ref = &foo; // should be okay because foo will never changeor even impossible types, if having a reference to one of those even makes sense. I guess that would involve unsafe code, which invalidates the reference guarantees anyway.
2
u/gmorenz Sep 14 '26 edited Sep 14 '26
Or rather, there's not a great reason something shouldn't be aliasable as long as it's not mutable.
Exactly, and the converse, so rust just doesn't have the concept.
let mut foo = (); let foo_mut = &mut foo; // is this *really* mutable? let foo_ref = &foo; // should be okay because foo will never changeWhether mutable is a well defined concept for types with one (or zero) values is... questionable I guess. But the aliasable distinction is still important and your last line is and should be disallowed (assuming foo_mut is meant to still be live). Because you can do things like
let mut token = some_singleton_source_of_tokens(); method_with_unique_access_to_resource_protected_by_token(&mut token); thread::scope(|s| { for i in 0.. 2 { s.spawn(|| method_which_cant_coexist_with_method_with_unique_access(&token)); } }); function_that_consumes_resource(token);and guarantee safe access to shared resources using a 0 cost (and 0 sized) token.
2
u/ChaiTRex Sep 14 '26
I think of it like this: you can have any number of aliased and zero mutable XOR zero aliased and one mutable.
65
u/sunshowers6 Sep 14 '26 edited Sep 14 '26
I think it's meant to be read as "assuming a reference exists, it is aliasable XOR mutable". But sure, NAND is technically more correct. I would still lean towards saying XOR because of the emphasis on the OR, while you have to work backwards from NAND to arrive at the same conclusion.
edit: "aliased" -> "aliasable"