Carbon Copy No.12: Generics Part IV Specialization #7144
wolffg
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Carbon Copy, April 2026
Here is the new Carbon Copy, your periodic update on the Carbon language!
Carbon Copy is designed for those people who want a high-level view of what's happening on the project. If you'd like to subscribe, you can join announce@carbon-lang.dev. Carbon Copy should arrive roughly (sometimes extremely roughly) every other month.
Toolchain update
In our last update, we showed interop, where Carbon called C++ seamlessly. Let's now take a look at C++ calling Carbon. (As we're all Carbon developers here, we call this "reverse interop".)
Here's our Carbon code for a vending machine base class:
In C++, we can extend that base class and call a method that returns a pointer:
See it in Compiler Explorer!
Spotlight: Specialization
In this spotlight, we're going to take a look at generics again. (Will we run out of generics topics in Carbon? It is not this day.)
C++ provides mechanisms for specialization in templates. In this example of C++, we're going to create a template to handle crossing various kinds of legendary animals. Our first is the jackalope:
C++ forbids the partial specialization of function templates, so we must use an overload. (Compiler explorer version.)
Carbon: One way, and it's consistent
Switching over to Carbon, the approach fundamentally changes. In Carbon, you cannot directly specialize types or functions. Instead, Carbon relies on interfaces as its only static open extension mechanism. Specialization is done by delegating to interfaces and defining parameterized
impldeclarations that apply to various types.To replicate the same logic in Carbon, and more, we start by defining an interface for the crossing operation.
Our generic looks about the same as C++, although we introduce a new keyword,
forall.The
forallkeyword is used to declare a parameterizedimpl(also known as a genericimpldeclaration). It introduces a list of compile-time generic parameters in square brackets immediately following theimplkeyword, formatted as:Now that we've made a generic legendary animal cross, let's start specializing around jackrabbits.
The next two
impls for antelope/antelope and jackrabbit/antelope are fully-specified, so they arefinal. We could write thefinalkeyword, but by fully-defining all the types (or having no parameters at all), they are effectively final, and function asfinal.A dilemma: Which came first, the jack or the lope?
We have a problem here, one familiar to template writers worldwide. Were I to cross a jackrabbit and an antelope (or rather a
Jackrabbitand anAntelope), what if more than oneimplmatches?Carbon uses a strict, step-by-step selection algorithm when multiple
impldeclarations match a type and interface. The process of determining which specialization (orimpl) to use is designed to guarantee implementation coherence, meaning the compiler must predictably choose the same implementation for a given query, regardless of which libraries are imported.When crossing ancestors in our example, we have
Jackrabbitfallback, andWhen figuring out which specialization to use, there are three rules. Let's take a look at each one.
Rule 1:
finalruleThe first rule here is the
finalrule, not the last rule, if you follow my drift.finalrule: Find afinalimplementation (or, as above, effectively final).In this case, the final rule does the work here. It chooses
impl Jackalope as CrossableWith(Antelope).Rule 2: Overlapping rule
Consider this case where we’re trying to create a skvader, the legendary Swedish hare-grouse:
In this case, with two non-final methods, the Overlap rule applies.
finalimpls match, Carbon evaluates all matching non-final impls based on their "type structure", called the "overlap rule".implwith question marks (?).implthat has a concrete type (a non-?) at that first difference is considered the most specific and wins.For our example above, the (
Hare?) example would be chosen as compared to (?,Grouse), since (Hare?) has the only non-? in the arguments going left-to-right. (Carbon explorer example.)Rule 3: Prioritization rule
Sometimes, multiple
impldeclarations will have the exact same type structure (that is, they overlap without one being strictly more specific). If this happens, Carbon requires that all of thoseimpldeclarations be grouped together in the samematch_firstblock (also called a prioritization block).implin the exact order they are listed. (Note: As of today, this is not implemented in the toolchain.)You can see here we've prioritized
HorseyvsSwimmyto match.Final Thoughts
Specialization in Carbon only applies to interfaces, and when it does, there are three simple rules to remember for managing specialization ordering:
finalruleAnd that's it!
Recent proposals and issues
If you want to keep up on Carbon’s proposals and issues, follow "Last Week In Carbon". Check out the RSS feed!
Recently accepted proposals including:
Recently closed leads issues including:
Wrap-up
Don't forget to subscribe! You can join announce@carbon-lang.dev. If you have comments or would like to contribute to future editions of Carbon Copy, please reach out. And, always, join us any way you can!
Next year in Andalusia,
Wolff, Josh, and the Carbon team
All reactions