Dave Herman's recent talk in Rust said that they borrowed this property from C++. I couldn't find anything around the topic. Can somebody please explain what monomorphisation means?
4 Answers
Monomorphization means generating specialized versions of generic functions. If I write a function that extracts the first element of any pair:
fn first<A, B>(pair: (A, B)) -> A {
let (a, b) = pair;
return a;
}
and then I call this function twice:
first((1, 2));
first(("a", "b"));
The compiler will generate two versions of first()
, one specialized to pairs of integers and one specialized to pairs of strings.
The name derives from the programming language term "polymorphism" — meaning one function that can deal with many types of data. Monomorphization is the conversion from polymorphic to monomorphic code.

- 388,571
- 95
- 1,107
- 1,366

- 2,046
- 1
- 13
- 5
-
3Is it another name for *static dispatch*? – tshepang Jun 08 '15 at 21:42
-
12@Tshepang Not really, it's more like the difference between C++ templates and Java generics. – Tavian Barnes Jun 08 '15 at 21:50
-
Seems to me to be the same as what we'd simply call (implicit) template specialisation in C++. Not to be confused with monomorphism, which would be the logical opposite of polymorphism in the sense of dealing with a subtype through it's parent's interface. – stellarpower May 05 '16 at 17:18
-
1@tshepang Static dispatch is a form of monomorphisation, specifically monomorphisation of ad hoc polymorphism. Ad hoc polymorphism takes the form of traits in Rust and interfaces in C++ and Java. Everyone else here is referring to monomorphisation of parametric polymorphism, which are called 'generics' in Rust and Java and 'templates' in C++, and which is very different from static dispatch because parametric polymorphism is very different from ad hoc polymorphism. Note that Java doesn't monomorphise anything, only Rust and C++ do. Specifically, (continued) – Han Seoul-Oh May 10 '21 at 19:12
-
2(continued) Rust and C++ use 'specialization' to monomorphise parametric polymorphism, as the accepted answer discusses, and by default use static dispatch to monomorphise ad hoc polymorphism. They also let you choose dynamic dispatch by using [`dyn`](https://doc.rust-lang.org/std/keyword.dyn.html) in Rust or virtual methods in C++. By contrast, Java uses dynamic dispatch for everything, even generics aka parametric polymorphism. – Han Seoul-Oh May 10 '21 at 19:27
Not sure if anyone is still looking at this, but the Rust documentation actually does mention how it achieves no cost abstraction through this process. From Performance of Code Using Generics:
You might be wondering whether there is a runtime cost when you’re using generic type parameters. The good news is that Rust implements generics in such a way that your code doesn’t run any slower using generic types than it would with concrete types.
Rust accomplishes this by performing monomorphization of the code that is using generics at compile time. Monomorphization is the process of turning generic code into specific code by filling in the concrete types that are used when compiled.
In this process, the compiler does the opposite of the steps we used to create the generic function in Listing 10-5: the compiler looks at all the places where generic code is called and generates code for the concrete types the generic code is called with.
Let’s look at how this works with an example that uses the standard library’s Option enum:
let integer = Some(5); let float = Some(5.0);
When Rust compiles this code, it performs monomorphization. During that process, the compiler reads the values that have been used in Option instances and identifies two kinds of Option: one is i32 and the other is f64. As such, it expands the generic definition of Option into Option_i32 and Option_f64, thereby replacing the generic definition with the specific ones.
The monomorphized version of the code looks like the following. The generic Option is replaced with the specific definitions created by the compiler:
// Filename: src/main.rs enum Option_i32 { Some(i32), None, } enum Option_f64 { Some(f64), None, } fn main() { let integer = Option_i32::Some(5); let float = Option_f64::Some(5.0); }
Because Rust compiles generic code into code that specifies the type in each instance, we pay no runtime cost for using generics. When the code runs, it performs just as it would if we had duplicated each definition by hand. The process of monomorphization makes Rust’s generics extremely efficient at runtime.

- 24,552
- 19
- 101
- 135

- 381
- 3
- 3
-
3Welcome to Stack Overflow and thanks for the answer. When providing an aswer that mostly consists of a link, it's generally helpful to briefly summarize the content of the linked article. That way your post remains useful if the link becomes broken. You're also more likely to get upvotes on your answer that way. – New Pagodi Nov 07 '18 at 16:19
-
2"no cost abstraction" is very questionable characterization; there is cost in larger binary size of the program and the time needed to compile. – user7610 Apr 26 '21 at 20:03
-
@user7610 Zero cost abstraction isn't new concept and Bjarne defined it pretty well: "What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better." Option
is a perfect example of that. It completely vanishes in the binary, it's either a valid T or a null. Of course you can make a silly argument that there's still a cost. You have to actually type those letters after all. But then the only cost-free program is one you don't write. – David Triebe Jul 06 '21 at 15:40 -
It was the wording of "no cost abstraction" that prompted me to write the previous comment. Nothing is entirely without cost, and the best we can is to make tradeoffs in shifting the cost around where it hurts less or is practicable to pay. I am aware of Bjarne's concept of zero cost abstraction, defined precisely the way you said. – user7610 Jul 06 '21 at 21:34
-
I think the more important cost here is that this also blows up cache requirements and makes it easier to miss the instruction cache therefore slowing the application in some circumstances. – Luxalpa Mar 31 '22 at 06:57
There is a nice explanation of monomorphization in the Rust Book
Monomorphization is the process of turning generic code into specific code by filling in the concrete types that are used when compiled.
From the book example, if you have defined variables with Some
:
let integer = Some(5); let float = Some(5.0);
When Rust compiles this code, it performs monomorphization. During that process, the compiler reads the values that have been used in
Option<T>
instances and identifies two kinds ofOption<T>
: one isi32
and the other isf64
. As such, it expands the generic definition ofOption<T>
intoOption_i32
andOption_f64
, thereby replacing the generic definition with the specific ones.The monomorphized version of the code looks like the following. The generic
Option<T>
is replaced with the specific definitions created by the compiler:Filename: src/main.rs
enum Option_i32 { Some(i32), None, } enum Option_f64 { Some(f64), None, } fn main() { let integer = Option_i32::Some(5); let float = Option_f64::Some(5.0); }

- 388,571
- 95
- 1,107
- 1,366

- 4,202
- 1
- 28
- 37
Not sure about this; could you link to the talk? It might have been an offhanded remark.
Herman might have coined a term for something like template specialization, which generates types/objects which are mutually unrelated (not-polymorphic or "monomorphic") from the template, which is a polymorphic structure.

- 134,909
- 25
- 265
- 421