Rust Permanent/Stable Type Identifiers
I have an idea related to #3435 and #3470 that differs from both of them.
The Idea
The idea is that Rust would add permanent identifiers for every type. These identifiers would be derived from the full path of a type, i.e., the identifier for std::vec::Vec would be derived from the path std::vec::Vec and not from the internal structure of std::vec::Vec or its memory footprint, only its path.
This permanent identifier would not change when you change your job or move homes, just as a national identification number does not change when you make those changes.
For example, the permanent identifier for Vec would be found by hashing the path of the type.
hash("std::vec::Vec") → permanent identifier for `Vec`
hash("my_crate::MyType") → permanent identifier for `MyType`
hash("std::vec::Vec") + hash("i32") → permanent identifier for `Vec`
What This Is NOT
This is not a stable ABI: The memory layout of Vec can remain unstable while the identifier that is telling you that Vec is of type i32 is stable. These two concepts exist at different layers.
Also, derived identifiers are not a derivation from the real structure of the type. For example, an identifying hash value of Vec does not change if the implementation of Vec changes.
How it Works
-
The compiler will assign the hash based on the full path to the type, and it will do so deterministically. There will be no manual hash value assigned and no central authority to assign hashes.
-
Generics are composable; that is to mean that the programmer will still write
Vecas they have been doing, and from there the compiler will derive the permanent identifier.
hash(Vec) = hash("std::vec::Vec") + hash("i32")
hash(Vec) = hash("std::vec::Vec") + hash("std::string::String")
The programmer does not need to do anything. It's perfectly see-through.
No collisions between crates:
hash("my_crate::User") ≠ hash("other_crate::User")
Paths in Rust are always unique, by definition.
When does the hash change? It only changes if how it was computed is changed explicitly. It is not affected by updates to rustc, assuming no changes were made. It is an explicit breaking change — similar to semver.
How it differs from #3435 and #3470
- #3470 (crABI) resolves issues regarding inter-language memory layout and representation, but does not provide a method of formally defining stable type identifiers.
- #3435 (export) deals with how to export symbol information dynamically. It requires stable identifiers, but also does not define them.
- The proposal presented in this document will provide the missing piece, which is an unambiguous, deterministic identifier for all types.
Importance
The use of stable type signatures is critical to having Rust-to-Rust dynamic linkage, as the absence of stable type information means that any dynamic linkage would require unsafe FFI in Rust, and it creates a major source of pain when building plugin systems. Additionally, crABI and export will have no foundation to work from for stable symbol (and possibly ABI) mangling. Therefore, the proposal presented here is the first concrete step toward establishing a stable ABI while not breaking anything in the present.
Outstanding Issues
The exact algorithm for combining generics having more than one type parameter is not yet resolved. Also unresolved is how combine interacts with types that have generics which are defaulted (such as HashMap).
This idea was raised here because I think it needs more technical evolution than I could do on my own. I am looking for input as to whether this direction has been investigated to date and, if so, what the status of that discussion is.