Link to slides: slides.com/sunjay/coherence-in-chalk
Link to slides: slides.com/sunjay/coherence-in-chalk
@sunjay03
Your Code
Lots of cool stuff I don't know about
Lots of cool stuff I don't know about
Machine Code
Machine Code
Current Traits Implementation
@sunjay03
Your Code
Lots of cool stuff I don't know about
Lots of cool stuff I don't know about
Machine Code
Machine Code
New Traits Implementation
Your Code
Chalk
Machine Code
Machine Code
Current Traits Implementation
Logic Programming!
@sunjay03
@sunjay03
trait FavoriteColor {
fn fav() -> &'static str;
}
struct Sunjay;
mod summer {
use super::*;
impl FavoriteColor for Sunjay {
fn fav() -> &'static str { "yellow" }
}
}
mod winter {
use super::*;
impl FavoriteColor for Sunjay {
fn fav() -> &'static str { "blue" }
}
}
Conflicting Implementations
@sunjay03
// Uses Hash impl A
fn insert<T: Hash>(...)
// Uses Hash impl B
fn get<T: Hash>(...)
The Hash Table Problem
// In the nom crate
impl Iterator for &[u8] { ... }
// In the serde crate
impl Iterator for &[u8] { ... }
Multiple Dependency Versions
Ecosystem Split
pub struct Foo;
// Only I can add this impl
// because Foo is MY type
impl Display for Foo { ... }
Backwards Compatibility
// In crate A:
trait Foo { ... }
impl<T> Foo for T { ... }
// In crate B:
struct Bar { ... }
// This impl is more specialized
impl Foo for Bar { ... }
// If crate C uses both A and B,
// a single, correct impl should
// always be used consistently
Specialization
@sunjay03
MyTrait::foo() // <-- Maps to ONE implementation
impl<T> MyTrait for T { ... } // <-- Can only be written in ONE place
@sunjay03
by boats (@withoutboats)
@sunjay03
The Orphan Check
+
The Overlap Check
@sunjay03
@sunjay03
The OrphanChecker in
The orphan_check function and the orphan_check_trait_ref function in
@sunjay03
Given an impl of the form impl<T0…Tn> Trait<P1…Pn> for P0, the impl is allowed if:
@sunjay03
impl<T, U, V, ...> MyTrait<P1...Pn> for P0 { ... }
Impl Type Parameters
Trait
Trait Type Parameters
Implemented Type
@sunjay03
impl<T, U, V, ...> MyTrait<P1...Pn> for P0 { ... }
Is this locally defined in the current crate or is this an Upstream Trait?
At least one local type
Must not contain any of the type parameters T, U, V, ...
Local Trait: Good To Go 🎉
Upstream Trait: Check P0, P1, P2, ..., Pn
Impl Type Parameters
If any of these conditions aren't met, the impl is considered an orphan impl
trait Foo { }
impl<T: Copy> Foo for T { }
impl<T: Eq> Foo for T { }
@sunjay03
@sunjay03
fact
rule
conclusion
👨🏽 💖 🍬
Provable because of our fact and rule
"Sunjay loves cake"
"___ loves candy if ___ loves cake"
"Sunjay loves candy"
@sunjay03
loves(sunjay, cake)
loves(T, candy) :- loves(T, cake)
loves predicate = 💖
if
?- loves(sunjay, candy)
Yes
Answer
Query
@sunjay03
// Each type T implements MyTrait
forall<T> { Implemented(T: MyTrait) }
forall<T> describes all types T
Means "T implements MyTrait"
// There is at least one type T
// that implements MyTrait
exists<T> { Implemented(T: MyTrait) }
exists<T> says that there is some T
forall<T> { ... }
exists<T> { ... }
@sunjay03
impl Foo for Bar { ... }
Implemented(Bar: Foo)
@sunjay03
// In crate "people":
extern crate favorites;
// In crate "favorites":
pub struct Taco { }
pub trait FavoriteColor {
fn fav() -> &'static str;
}
impl<T: Copy> FavoriteColor for T {
fn fav() -> &'static str { "purple" }
}
// In crate "std":
pub trait Copy { }
use favorites::*;
struct Sunjay;
impl FavoriteColor for Sunjay {
fn fav() -> &'static str { "red" }
}
struct Manish;
impl FavoriteColor for Manish {
fn fav() -> &'static str { "orange" }
}
IsLocal(Sunjay)
IsLocal(Manish)
Implemented(Sunjay: FavoriteColor)
Implemented(Manish: FavoriteColor)
IsUpstream(Taco)
forall<T> { Implemented(T: FavoriteColor)
:- Implemented(T: Copy) }
DependsOn(people, favorites)
DefinedIn(Sunjay, people)
DefinedIn(Manish, people)
"if"
upstream
current crate
@sunjay03
@sunjay03
// In crate "foo"
pub trait MyTrait<T, U> { }
pub struct Foo { }
// In crate "bar"
extern crate foo;
use foo::*;
struct Bar { }
impl<T> MyTrait<Bar, T> for Foo { }
// Type parameters in order: Foo, Bar, T
impl type parameter
upstream trait
first local type
only fully visible types before the first local type
Good to Go!
The Orphan Rules don't care about any of the types after the first local type
fully visible = no type parameters (e.g. Foo<Bar> but not Foo<T>)
@sunjay03
struct Turtle;
// Is LocalImplAllowed(Turtle: Display) provable?
// Yes. Turtle is a local type
impl Display for Turtle { ... }
// Is LocalImplAllowed(Vec<Turtle>: Display) provable?
// No. Vec<T> is defined in std and the orphan rules
// say that only std can add impls for it
impl Display for Vec<Turtle> { ... }
@sunjay03
forall<Self, T, U> { LocalImplAllowed(Self: MyTrait<T, U>) }
forall<Self, T, U> {
LocalImplAllowed(Self: MyTrait<T, U>) :-
IsLocal(Self)
}
forall<Self, T, U> {
LocalImplAllowed(Self: MyTrait<T, U>) :-
IsFullyVisible(Self),
IsLocal(T)
}
forall<Self, T, U> {
LocalImplAllowed(Self: MyTrait<T, U>) :-
IsFullyVisible(Self),
IsFullyVisible(T),
IsLocal(U)
}
trait MyTrait<T, U> { }
Simulates "finding" the first local type
// In crate "foo":
pub struct Foo { }
// In crate "bar":
extern crate foo;
struct Bar { }
pub struct Spam<T, U> { ... }
IsFullyVisible(Foo)
IsFullyVisible(Bar)
// Notice that there isn't
// any IsFullyVisible(T)
forall<T, U> {
IsFullyVisible(Spam<T, U>) :-
IsFullyVisible(T),
IsFullyVisible(U)
}
// In crate "foo": (current)
pub struct Foo<T> { ... }
// In crate "bar":
extern crate foo;
struct Bar<T> { ... }
forall<T> { IsLocal(Foo<T>) }
@sunjay03
Fully Visible
Not sure if fully visible
Local
Upstream
Foo is local regardless of its type parameter
@sunjay03
@sunjay03
@sunjay03
Thank you Niko, boats, and the many others who have helped figure all of this out!
@sunjay03
Link to slides: slides.com/sunjay/coherence-in-chalk