Hacker News new | ask | show | jobs
by choeger 1262 days ago
Template specialization sometimes looks like monomorphization, but it is really a different thing. I would compare C++ templates more macros, as they tend to do way more (e.g., allow for overload resolution).
1 comments

Please elaborate. I agree C++ templates are more flexible in what they do (SFINAE etc.), but Rust generics and C++ templates still both use monomorphization
I wouldn't say that C++ templates use monomorphization, because there are no polymorphic functions to begin with. Monomorphization, as in "the standard FPL technique", comes after type checking. C++ template specialization precedes type checking.

Of course one can redefine the meaning of "polymorphism" and "monomorphization" to fit C++, but then these words lose nearly all meaning.

TIL. Thanks!

In my plebeian brain I just thought “monomorphization = static dispatch” / 0-cost abstraction (vs. just writing multiple versions of a function), which both Rust generics and C++ templates fall into.

Now I see that “monomorphization” has a specific definition in FPL

I'm not satisfied by your explanation here. What definition of 'polymorphism' are you using? Why would type checking need to precede monomorphisation? Additionally, how do C++ concepts fit into your beliefs?
This one:

https://en.m.wikipedia.org/wiki/Parametric_polymorphism

Note that it's called "parametric" because OO folks stole the word polymorphism for a completely different thing.

The idea of a polymorphic function is that it acts the same for all possible input values (for at least one parameter). This is captured by its type. If you look at a polymorphic function (say "f(x) = x" with the type "for all 'a. 'a -> 'a ") you can check that type once and you know that monomorphization works for any possible input.

Monomorphization is then the process to replace 'a with a concrete type to facilitate code generation. What it actually does, depends on your language of course. It might for instance decide how to pass arguments or compute offsets from record labels. Crucially, monomorphization in this sense never fails, at least not because you input the wrong type. The user doesn't need to know that monomorphization happens at all. It's an internal design choice of the compiler.

If you look at C++, template specialization is very visible. The template that represents the identity function doesn't have a type. Only after specialization, the user learns whether it was successful or not (e.g., because copying the type is not possible).

I never worked with concepts myself, but to my understanding, they are an attempt to generate more useful error messages. As far as I know, the concept declaration of a template might simply be wrong, there's no automatic check that guarantees that a template can be instantiated if I adhere to the contract, right? So the type check still has to happen after specialization and the user has to consider specialization in their mental model of the code.