Un atelier Rust · Édition d'ApprentissageA Rust Workshop · Learning Edition

Orphan rule & blanket impls Orphan rule & blanket impls

Pourquoi on ne peut pas tout implémenter partout : la cohérence. Et les patterns autour — le newtype pour contourner l'orphan rule proprement. Why you can't implement everything everywhere: coherence. And the patterns around it — the newtype to work around the orphan rule cleanly.

AudienceAudience
Dev maîtrisant traits, generics et dyn (Vol 5 №1–2) Dev fluent in traits, generics and dyn (Vol 5 №1–2)
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026 Jun 2026
≈ 18 min ●●●● TraitsCoherenceNewtype

Chapitre 1 en accès libre — la suite (ch. 2 à 5) est réservée. Chapter 1 free to read — the rest (ch. 2–5) is members-only.

01CadrageFraming3 min

Une implémentation, et une seule, pour tout le programme. C'est la cohérence.One implementation, and only one, for the whole program. That's coherence.

Deux numéros durant, on a implémenté des traits comme si de rien n'était. Mais une contrainte rôdait, évoquée au n°1 : on ne peut pas implémenter n'importe quel trait pour n'importe quel type. La raison est une garantie que Rust tient à tout prix — la cohérence : pour un trait et un type donnés, il existe au plus une implémentation dans tout le programme. Sans elle, deux bibliothèques pourraient donner au même type deux comportements incompatibles pour le même trait, et le compilateur, face à un appel, ne saurait laquelle choisir. L'orphan rule est le gardien de cette unicité : tu ne peux implémenter un trait pour un type que si tu possèdes au moins l'un des deux — le trait, ou le type.For two issues, we implemented traits as if nothing could go wrong. But a constraint lurked, hinted at in n°1: you can't implement just any trait for just any type. The reason is a guarantee Rust upholds at all costs — coherence: for a given trait and type, there is at most one implementation in the whole program. Without it, two libraries could give the same type two incompatible behaviors for the same trait, and the compiler, facing a call, wouldn't know which to choose. The orphan rule is the guardian of that uniqueness: you may implement a trait for a type only if you own at least one of the two — the trait, or the type.

L'orphan rule — au moins l'un des deux doit t'appartenirThe orphan rule — at least one of the two must be yours
// La règle : pour impl Trait for Type, tu dois POSSÉDER l'un des deux.

impl Surface for Cercle { /* ... */ }   // ✓ Surface est à toi (ou Cercle l'est)
impl Display for Cercle  { /* ... */ }   // ✓ Cercle est à toi (Display est std)

impl Display for Vec<i32> { /* ... */ }  // ✕ NI Display NI Vec ne sont à toi
//   error[E0117]: only traits defined in the current crate can be
//   implemented for types defined outside of the crate (orphan rule)

// les deux « étrangers » à la fois = interdit. sinon deux crates pourraient
// donner à Vec deux impl Display différentes — et laquelle gagnerait ?
Pourquoi « orphan » ?Why 'orphan'?
crate jolie-couleur
impl Display for Vec<u8>
crate console-log
impl Display for Vec<u8>
ton programme dépend des deuxyour program depends on both
println!("{}", mon_vec)
??? quelle des deux impl ?which of the two impls?
→ conflit insoluble : l'orphan rule l'interdit en amont→ unsolvable conflict: the orphan rule forbids it upstream

Une implémentation est « orpheline » quand ni le trait ni le type ne sont définis dans ta crate — elle n'a de parent nulle part. Le danger est concret : imagine que la crate jolie-couleur et la crate console-log implémentent toutes deux Display pour Vec<u8>. Un programme qui dépend des deux contiendrait deux impl rivales du même couple (trait, type). Que devrait afficher println!("{}", mon_vec) ? Il n'y a pas de bonne réponse — et Rust refuse de choisir au hasard. L'orphan rule rend la situation impossible à créer : au plus une des deux crates peut écrire cette impl, et seulement si elle possède le type.An implementation is 'orphan' when neither the trait nor the type is defined in your crate — it has a parent nowhere. The danger is concrete: imagine the pretty-color crate and the console-log crate both implement Display for Vec<u8>. A program depending on both would contain two rival impls of the same (trait, type) pair. What should println!("{}", my_vec) print? There's no right answer — and Rust refuses to choose at random. The orphan rule makes the situation impossible to create: at most one of the two crates can write that impl, and only if it owns the type.

Le réflexe du numéroThe issue's reflex

« Le trait que je veux implémenter, ou le type sur lequel je l'implémente : au moins l'un des deux est-il à moi ? » Oui → l'impl est permise. Non (les deux viennent de crates externes) → l'orphan rule la refuse, et il faut un détour : envelopper le type étranger dans un type à toi. Ce détour, c'est le newtype du Vol 3, qui revient ici jouer un rôle inattendu.'The trait I want to implement, or the type I implement it on: is at least one of them mine?' Yes → the impl is allowed. No (both come from external crates) → the orphan rule refuses it, and you need a detour: wrap the foreign type in a type of your own. That detour is Vol 3's newtype, returning here to play an unexpected role.

Une limite, pas une punition.A limit, not a punishment.

L'orphan rule frustre la première fois qu'on la rencontre — on voulait juste ajouter un petit Display sur un Vec. Mais c'est le prix d'une propriété précieuse : en Rust, ajouter une dépendance ne peut jamais changer en silence le comportement d'un type que tu utilises déjà. Les impl sont globales et uniques, donc prévisibles. La cohérence est ce qui rend l'écosystème composable sans conflits invisibles.The orphan rule frustrates the first time you meet it — you just wanted to add a small Display on a Vec. But it's the price of a precious property: in Rust, adding a dependency can never silently change the behavior of a type you already use. Impls are global and unique, hence predictable. Coherence is what makes the ecosystem composable without invisible conflicts.

🔒

La suite est réservée The rest is members-only

Le premier numéro est libre. Débloque tout The Rust Loop — tous les volumes, à vie — pour 5 €, paiement unique. The first issue is free. Unlock all of The Rust Loop — every volume, forever — for €5, one-time.

Retour au kiosqueBack to newsstand