Type Erasure in Rust
source link: https://belkadan.com/blog/2023/10/Type-Erasure-in-Rust/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Type Erasure in Rust
Rust traits have the neat property where you can use them either as generic bounds or as dynamic dispatch, with the &dyn MyTrait
syntax. The latter is necessary in heterogeneous scenarios, where you want to use multiple concrete types together that all implement a common trait. However, that requires that you have an instance, so that the reference actually “refers” to something. What if you have a trait with “static” requirements, like const
s or methods without &self
?
If the implementing types have instances, or are just marker types, you can wrap the base trait in a new trait, like in this stripped-down example from my work:
trait Parameters {
const SECRET_KEY_LENGTH: usize;
fn generate() -> KeyMaterial<Secret>;
}
trait DynParameters {
fn secret_key_length(&self) -> usize;
fn generate(&self) -> KeyMaterial<Secret>;
}
impl<T: Parameters> DynParameters for T {
fn secret_key_length(&self) -> usize {
Self::SECRET_KEY_LENGTH
}
fn generate(&self) -> KeyMaterial<Secret> {
Self::generate()
}
}
Now &dyn DynParameters
will work.
However, sometimes the types that conform to the trait don’t have instances to tie a new trait to. If so, take a step back and think about what dynamic dispatch is: a table of trait members that get looked up at run time. You can build a little wrapper type to do this manually:
trait Parameters {
const SECRET_KEY_LENGTH: usize;
fn generate() -> KeyMaterial<Secret>;
}
struct AnyParameters {
secret_key_length: usize;
generate: fn() -> KeyMaterial<Secret>;
}
impl AnyParameters {
fn new<T: Parameters>() -> Self {
Self {
secret_key_length: T::SECRET_KEY_LENGTH,
generate: T::generate, // we're not calling it, just referring to it
}
}
}
Generics
This is all well and good, but what if the type you need to abstract over isn’t a trait at all, but a generic struct? If the generic is just a marker type, we may be able to get away with substituting our own marker type:
struct KeyMaterial<T> {
data: Box<[u8]>,
kind: PhantomData<T>,
}
impl KeyMaterial<()> {
fn erasing_kind_of<T>(other: KeyMaterial<T>) -> Self {
Self {
data: other.data,
kind: PhantomData,
}
}
}
But usually there are some additional operations on the type that we might need. In that case we’ll combine the two techniques: we’ll copy over data from the input struct, and also include a manual dispatch table.
struct KeyMaterial<T> {
data: Box<[u8]>,
kind: PhantomData<T>,
}
trait KeyKind {
fn key_length(key_type: KeyType) -> usize;
}
struct AnyKeyMaterial {
// Data from KeyMaterial<T>
data: Box<[u8]>,
// Operations from T: KeyKind
key_length: fn(KeyType) -> usize;
}
impl AnyKeyMaterial {
fn erasing_kind_of<T: KeyKind>(other: KeyMaterial<T>) -> Self {
Self {
data: other.data,
key_length: T::key_length,
}
}
}
And now you have a struct that can be used to represent heterogeneous KeyMaterials. (Never mind that the example no longer makes sense.)
This pattern isn’t very complicated, but I didn’t see it written down in one place for Rust, hence this post. (Swift folks who’ve been around for a few years are pretty familiar with similar patterns, though they’re rarer now that Swift’s any
types—the equivalent of dyn
—aren’t as limited as they were in the past.)
This entry was posted on October 23, 2023 and is filed under Technical. Tags: Rust
Recommend
-
36
In this post I'd like to discuss the concepts of type erasure and reification in programming languages. I don't intend to dive very deeply into the specific rules of any particular language; rathe...
-
29
I’ve been learning more about Scala’s type system, and last week, I hit some of its limitations. In this post, I’ll be covering an issue called type erasure . If you’re interested in understanding gen...
-
8
Friday Q&A 2017-12-08mikeash.com: just this guy, you know? Friday Q&A 2017-12-08: Type Erasure in Swift by Mike Ash This article is als...
-
9
GADTs with type erasure in coq-of-ocaml June 19, 2020 coq-of-ocaml is a compiler from the OCaml language to
-
6
Type Erasure for Unopinionated Interfaces in C++ May 22, 2018 24 minute read The life of a library designer is hard: She must make decisions about the components and interfaces the library provide...
-
3
Menu C++ Type Erasure Lu Pan | 15 Apr 2021 | 3 min read
-
4
Duck Typing vs Type Erasure 原文URL: http://nullprogram.com/blog/2014/04/01/ 假设有这么一个 C++ 类. #include <iostrea...
-
4
This is part 1 of a two-part series. This part deals with overcoming type erasure. In Part 2, we will see what EqualsVerifier can do with this generic type infor...
-
2
What's the 'any' keyword? Understanding Type Erasure in Swift What's the "any" keyword? Understanding Type Erasure in Swift Published on 12 Sep 2022 The concept o...
-
4
TypeScript 学习笔记01 类型擦除
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK