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?
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.
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.
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:
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.
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 of Option<T>: one is i32 and the other
is f64. As such, it expands the generic definition of Option<T> 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<T> is replaced with the specific definitions created by the compiler: