What is type erasure
Type erasure, in general, is a programming technique by which the explicit type information is removed from the program. It is a type of abstraction that ensures that the program does not explicitly depend on some of the data types.
The aim here is to increase the level of abstraction — instead of writing some type-specific code, perhaps serveral versions of it for different types, we can write just one version that is more abstract, and expressed the concept — for example, instead of writing a function whose interface expresses the concept sort an array of integers, we want to write a more abstract function, sort any array.
From example to generalization
In c++, std::function
is a general-purpose polymorphic function wrapper, or a general callable object. It’s used to store any callable entity such as a function, a lambda expression, a functor(an object with the operator()), or a memeber function pointer.
We can now see type erasure in its more general form: it is an abstraction for many different implementations that all provide the same behavior.
Type erasue as a design pattern?
type erasure offers an non-intrusive way to separate the interface from the implementation. It’s different from inheritance. We can say that type erasure provides “external polyorphism”: there is no unifying hierarchy required, and the set of types that can be used to implement a particular abstraction is extensible, not limited to just classes derived from a common base.
Why doesn’t type erasure completely replace inheritance in C++?
- performance, high-performance implementations of type erasure became available only recently.
- convenience.
Type erasure as an implementation technique
Type erasure is a great tool for breaking dependencies between components of a large system.
For example, we are building a large distributed software system, so one of our core components it the network communication layer:
Now, in one specific application, we have a need to process the data packets before and after they are sent across the network:
Is it a dependency nightmare: the low-level library now has to built with the apply_processing
function from the specific application. Even worse, all other programs that do not require this functionality must still be compiled and linked with this code, even if they never set needs_processing
.
While this problem can be handled the ‘old school’ way - with some function pointer or (worse) global variables, type erasure offers an elegant solution:
This is an example of the strategy design pattern, where the implementation of a particular behavior can be chosen at run-time.
How is type erasure implemented in C++?
Very old type erasure
The major downside of this C approach is that the programmer is wholly responsible for ensuring that all the pieces of the type-erased code are consistent.
In C++, we can do a lot better, but the idea is still the same: the erased type is reified by the implementation of some type-specific code that is invoked through the type-agnostic interface. The key difference is that we are going to force the compiler to generate this code for use. There are, fundamentally, two techniues that can be used. The first one relies on run-time polymorphism(inheritance), and the second one uses template magic.
Type erasure using inheritance
Befor we learn the other (usually more efficient) way to implement type erasure, we have to address one glaringly obvious inefficiency in our design: every time we create or delete a shared pointer or a std::function
object that is implemented as described above, we must allocate and deallocate memory for the derived object that conceals the erased type.
Type erasue without memory allocation
Type erasure without inheritance
The function template that remains the information about the erased type is invoke_destroy()
, note that is a static function.
We can use vtable
to sim inheritance to avoid the smartptr bloat.
Example in real world
LLVM new PassManager
manage new pass (PassInfoMixin
template pass) by type erase( concepts and model)
The code location is at
reference
- concepts and model(template) in one class that represent the concept
- C++ template - the complete guide 2nd ediditon chapter 22
- andrzej’s series on type erasure part1 part2 part3 part4