`MaybeInvalid<T>` - separate concepts of uninitialized memory and invalid values
I don’t think I’m fully understanding how this is supposed to make freeze any easier, but I’m also not quite getting the proposed type’s properties in the first place.
Note that even for valid types, uninitialized bytes are often an option. For example for a type like MaybeUninit<u8> itself; or for the padding bytes in a struct (if it has any padding bytes).
In my mental model, a value in Rust (only speaking of the shallow data, not data behind pointers) consists - basically - just of a sequence of bytes[1], but every byte of memory has not only the 256 different values (from 0 to 255) for concrete numerical values, but also an additional 256’th value that we can call “uninitialized”. (In LLVM this corresponds to the value “undef”.) In Rust types, a byte is thus represented by MaybeUninit<u8>.
A struct or enum value, consisting of a (usually fixed-length) sequence of bytes usually then comes with additional restrictions on the possible values of its bytes. These restrictions could be independent for each byte, but they can also interdepend.
For example u8 is one byte, and restricted to not be undef.
For people worrying about undef not existing at run-time – that’s not really an issue in the abstract machine model. There it really is an undef separate from all other possible values for a byte; just the rules that disallow you from “reading” undef (in a sense of trying to read it as any other concrete byte value 0 through 255) mean that in lowering it into concrete machine code, it never actually needs to be written or read at run-time.
Now, MaybeUninit<T> lifts all the byte-level restrictions that the type T introduces on its (shallow) data. In this mental mode, MaybeUninit does nothing else but allow invalid values. Whether or not uninit byte values are allowed depends on the type – i.e. for certain T in certain bytes (and under perhaps certain conditions of what the other bytes may be) undef is allowed or not allowed in plain T; of course it’s always allowed anywhere in MaybeUninit<T> because that allow all invalid values, too.
But now you propose MaybeInvalid<T> and write down that “non-fixed value” should still be disallowed (by “non-fixed” I suppose you’re referring to undef byte values?) And this doesn’t fit my mental model well, because <T> itself may have never rules some undef bytes. So I’d assume you might mean that it allows additional invalid values that aren’t undefined, but never adds additional undefined values?
But what are the exact rules?
Some example questions that precise rules will have to be able to give an answer for: (click for more details)
ignoring additional information like provenance ↩︎
assuming straightforward, repr-
C-like layout of the tuple! ↩︎
Discussion in the ATmosphere