PageSourceSearch

https://noir-lang.org/docs/assets/js/0a1b032e.c908c9e3.js

js noir-lang.org collected 2026-10-03 22:49:48 UTC 29,786 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[179],{48020(e,n,t){t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"language/traits","title":"Traits","description":"Traits in Noir can be used to abstract out a common interface for functions across several data types.","source":"@site/versioned_docs/version-v1.0.0-beta.26/language/traits.md","sourceDirName":"language","slug":"/language/traits","permalink":"/docs/v1.0.0-beta.26/language/traits","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-beta.26/language/traits.md","tags":[],"version":"v1.0.0-beta.26","frontMatter":{"title":"Traits","description":"Traits in Noir can be used to abstract out a common interface for functions across several data types.","keywords":["noir programming language","traits","interfaces","generic","protocol"]},"sidebar":"sidebar","previous":{"title":"Data Bus","permalink":"/docs/v1.0.0-beta.26/language/data_bus"},"next":{"title":"Attributes","permalink":"/docs/v1.0.0-beta.26/language/attributes"}}');var r=t(74848),i=t(28453);const s={title:"Traits",description:"Traits in Noir can be used to abstract out a common interface for functions across several data types.",keywords:["noir programming language","traits","interfaces","generic","protocol"]},l=void 0,o={},c=[{value:"Overview",id:"overview",level:2},{value:"Where Clauses",id:"where-clauses",level:2},{value:"Trait bounds",id:"trait-bounds",level:2},{value:"Invoking trait methods",id:"invoking-trait-methods",level:2},{value:"As Trait Syntax",id:"as-trait-syntax",level:2},{value:"Generic Implementations",id:"generic-implementations",level:2},{value:"Generic Trait Implementations With Where Clauses",id:"generic-trait-implementations-with-where-clauses",level:3},{value:"Generic Traits",id:"generic-traits",level:2},{value:"Associated Types and Constants",id:"associated-types-and-constants",level:3},{value:"Trait Methods With No <code>self</code>",id:"trait-methods-with-no-self",level:2},{value:"Default Method Implementations",id:"default-method-implementations",level:2},{value:"Impl Specialization",id:"impl-specialization",level:2},{value:"Overlapping Implementations",id:"overlapping-implementations",level:2},{value:"Trait Coherence",id:"trait-coherence",level:2},{value:"The Newtype Pattern",id:"the-newtype-pattern",level:3},{value:"Trait Inheritance",id:"trait-inheritance",level:3},{value:"Trait Aliases",id:"trait-aliases",level:3},{value:"Generic Trait Aliases",id:"generic-trait-aliases",level:4},{value:"Trait Alias Where Clauses",id:"trait-alias-where-clauses",level:4},{value:"Visibility",id:"visibility",level:3}];function d(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines\nthe interface of several methods contained within the trait. Types can then implement this trait by providing\nimplementations for these methods. For example in the program:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"struct Rectangle {\n    width: Field,\n    height: Field,\n}\n\nimpl Rectangle {\n    fn area(self) -> Field {\n        self.width * self.height\n    }\n}\n\nfn log_area(r: Rectangle) {\n    println(r.area());\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["We have a function ",(0,r.jsx)(n.code,{children:"log_area"})," to log the area of a ",(0,r.jsx)(n.code,{children:"Rectangle"}),". Now how should we change the program if we want this\nfunction to work on ",(0,r.jsx)(n.code,{children:"Triangle"}),"s as well?:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"struct Triangle {\n    width: Field,\n    height: Field,\n}\n\nimpl Triangle {\n    fn area(self) -> Field {\n        self.width * self.height / 2\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Making ",(0,r.jsx)(n.code,{children:"log_area"})," generic over all types ",(0,r.jsx)(n.code,{children:"T"})," would be invalid since not all types have an ",(0,r.jsx)(n.code,{children:"area"})," method. Instead, we can\nintroduce a new ",(0,r.jsx)(n.code,{children:"Area"})," trait and make ",(0,r.jsx)(n.code,{children:"log_area"})," generic over all types ",(0,r.jsx)(n.code,{children:"T"})," that implement ",(0,r.jsx)(n.code,{children:"Area"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Area {\n    fn area(self) -> Field;\n}\n\nfn log_area<T>(shape: T) where T: Area {\n    println(shape.area());\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["We also need to explicitly implement ",(0,r.jsx)(n.code,{children:"Area"})," for ",(0,r.jsx)(n.code,{children:"Rectangle"})," and ",(0,r.jsx)(n.code,{children:"Triangle"}),". We can do that by changing their existing\nimpls slightly. Note that the parameter types and return type of each of our ",(0,r.jsx)(n.code,{children:"area"})," methods must match those defined\nby the ",(0,r.jsx)(n.code,{children:"Area"})," trait."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl Area for Rectangle {\n    fn area(self) -> Field {\n        self.width * self.height\n    }\n}\n\nimpl Area for Triangle {\n    fn area(self) -> Field {\n        self.width * self.height / 2\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Now we have a working program that is generic over any type of Shape that is used! Others can even use this program\nas a library with their own types - such as ",(0,r.jsx)(n.code,{children:"Circle"})," - as long as they also implement ",(0,r.jsx)(n.code,{children:"Area"})," for these types."]}),"\n",(0,r.jsx)(n.h2,{id:"where-clauses",children:"Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["As seen in ",(0,r.jsx)(n.code,{children:"log_area"})," above, when we want to create a function or method that is generic over any type that implements\na trait, we can add a where clause to the generic function."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn log_area<T>(shape: T) where T: Area {\n    println(shape.area());\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the ",(0,r.jsx)(n.code,{children:"+"}),"\noperator. Similarly, we can have multiple trait constraints by separating each with a comma:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn foo<T, U>(elements: [T], thing: U) where\n    T: Default + Add + Eq,\n    U: Bar,\n{\n    let mut sum = T::default();\n\n    for element in elements {\n        sum += element;\n    }\n\n    if sum == T::default() {\n        thing.bar();\n    }\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"trait-bounds",children:"Trait bounds"}),"\n",(0,r.jsx)(n.p,{children:"A shorter syntax for specifying trait bounds directly on generic types is available. For example, this code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn log_area<T>(shape: T) where T: Area {\n    println(shape.area());\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"can also be written like this:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn log_area<T: Area>(shape: T) {\n    println(shape.area());\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Both are equivalent. Using ",(0,r.jsx)(n.code,{children:"where"})," is preferable when there are many trait bounds and it's clearer to have\nthem separate from the types the are applying bounds to."]}),"\n",(0,r.jsx)(n.h2,{id:"invoking-trait-methods",children:"Invoking trait methods"}),"\n",(0,r.jsxs)(n.p,{children:["As seen in the previous section, the ",(0,r.jsx)(n.code,{children:"area"})," method was invoked on a type ",(0,r.jsx)(n.code,{children:"T"})," that had a where clause ",(0,r.jsx)(n.code,{children:"T: Area"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["To invoke ",(0,r.jsx)(n.code,{children:"area"})," on a type that directly implements the trait ",(0,r.jsx)(n.code,{children:"Area"}),", the trait must be in scope (imported):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"use geometry::Rectangle;\n\nfn main() {\n    let rectangle = Rectangle { width: 1, height: 2};\n    let area = rectangle.area();
1 // Error: the compiler doesn't know which `area` method this is\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The above program errors because there might be multiple traits with an ",(0,r.jsx)(n.code,{children:"area"})," method, all implemented\nby ",(0,r.jsx)(n.code,{children:"Rectangle"}),", and it's not clear which one should be used."]}),"\n",(0,r.jsx)(n.p,{children:"To make the above program compile, the trait must be imported:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"use geometry::Rectangle;\nuse geometry::Area; // Bring the Area trait into scope\n\nfn main() {\n    let rectangle = Rectangle { width: 1, height: 2};\n    let area = rectangle.area(); // OK: will use `area` from `geometry::Area`\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["An error will also be produced if multiple traits with an ",(0,r.jsx)(n.code,{children:"area"})," method are in scope. If both traits\nare needed in a file you can use the fully-qualified path to the trait:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"use geometry::Rectangle;\n\nfn main() {\n    let rectangle = Rectangle { width: 1, height: 2};\n    let area = geometry::Area::area(rectangle);\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"as-trait-syntax",children:"As Trait Syntax"}),"\n",(0,r.jsxs)(n.p,{children:["Rarely to call a method it may not be sufficient to use the general method call syntax of ",(0,r.jsx)(n.code,{children:"obj.method(args)"}),".\nOne case where this may happen is if there are two traits in scope which both define a method with the same name.\nFor example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Foo  { fn bar(); }\ntrait Foo2 { fn bar(); }\n\nfn example<T>()\n    where T: Foo + Foo2\n{\n    // How to call Foo::bar and Foo2::bar?\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["In the above example we have both ",(0,r.jsx)(n.code,{children:"Foo"})," and ",(0,r.jsx)(n.code,{children:"Foo2"})," which define a ",(0,r.jsx)(n.code,{children:"bar"})," method. The normal way to resolve\nthis would be to use the static method syntax ",(0,r.jsx)(n.code,{children:"Foo::bar(object)"})," but there is no object in this case and\n",(0,r.jsx)(n.code,{children:"Self"})," does not appear in the type signature of ",(0,r.jsx)(n.code,{children:"bar"}),' at all so we would not know which impl to choose.\nFor these situations there is the "as trait" syntax: ',(0,r.jsx)(n.code,{children:"<Type as Trait>::method(object, args...)"})]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn example<T>()\n    where T: Foo + Foo2\n{\n    <T as Foo>::bar();\n    <T as Foo2>::bar();\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"generic-implementations",children:"Generic Implementations"}),"\n",(0,r.jsxs)(n.p,{children:["You can add generics to a trait implementation by adding the generic list after the ",(0,r.jsx)(n.code,{children:"impl"})," keyword:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Second {\n    fn second(self) -> Field;\n}\n\nimpl<T> Second for (T, Field) {\n    fn second(self) -> Field {\n        self.1\n    }\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"You can also implement a trait for every type this way:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Debug {\n    fn debug(self);\n}\n\nimpl<T> Debug for T {\n    fn debug(self) {\n        println(self);\n    }\n}\n\nfn main() {\n    1.debug();\n}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"generic-trait-implementations-with-where-clauses",children:"Generic Trait Implementations With Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["Where clauses can be placed on trait implementations themselves to restrict generics in a similar way.\nFor example, while ",(0,r.jsx)(n.code,{children:"impl<T> Foo for T"})," implements the trait ",(0,r.jsx)(n.code,{children:"Foo"})," for every type, ",(0,r.jsx)(n.code,{children:"impl<T> Foo for T where T: Bar"}),"\nwill implement ",(0,r.jsx)(n.code,{children:"Foo"})," only for types that also implement ",(0,r.jsx)(n.code,{children:"Bar"}),". This is often used for implementing generic types.\nFor example, here is the implementation for array equality:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl<T, let N: u32> Eq for [T;
1 let N: u32] where T: Eq {\n    // Test if two arrays have the same elements.\n    // Because both arrays must have length N, we know their lengths already match.\n    fn eq(self, other: Self) -> bool {\n        let mut result = true;\n\n        for i in 0 .. self.len() {\n            // The T: Eq constraint is needed to call == on the array elements here\n            result &= self[i] == other[i];\n        }\n\n        result\n    }\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"Where clauses can also be placed on struct implementations.\nFor example, here is a method utilizing a generic type that implements the equality trait."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"struct Foo<T> {\n    a: u32,\n    b: T,\n}\n\nimpl<T> Foo<T> where T: Eq {\n    fn eq(self, other: Self) -> bool {\n        (self.a == other.a) & self.b.eq(other.b)\n    }\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"generic-traits",children:"Generic Traits"}),"\n",(0,r.jsx)(n.p,{children:"Traits themselves can also be generic by placing the generic arguments after the trait name. These generics are in\nscope of every item within the trait."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Into<T> {\n    // Convert `self` to type `T`\n    fn into(self) -> T;\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["When implementing generic traits the generic arguments of the trait must be specified. This is also true anytime\nwhen referencing a generic trait (e.g. in a ",(0,r.jsx)(n.code,{children:"where"})," clause)."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"struct MyStruct {\n    array: [Field; 2],\n}\n\nimpl Into<[Field; 2]> for MyStruct {\n    fn into(self) -> [Field; 2] {\n        self.array\n    }\n}\n\nfn as_array<T>(x: T) -> [Field; 2]\n    where T: Into<[Field; 2]>\n{\n    x.into()\n}\n\nfn main() {\n    let array = [1, 2];\n    let my_struct = MyStruct { array };\n\n    assert_eq(as_array(my_struct), array);\n}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"associated-types-and-constants",children:"Associated Types and Constants"}),"\n",(0,r.jsx)(n.p,{children:"Traits also support associated types and constraints which can be thought of as additional generics that are referred to by name."}),"\n",(0,r.jsxs)(n.p,{children:["Here's an example of a trait with an associated type ",(0,r.jsx)(n.code,{children:"Foo"})," and a constant ",(0,r.jsx)(n.code,{children:"Bar"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait MyTrait {\n    type Foo;\n\n    let Bar: u32;\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Now when we're implementing ",(0,r.jsx)(n.code,{children:"MyTrait"})," we also have to provide values for ",(0,r.jsx)(n.code,{children:"Foo"})," and ",(0,r.jsx)(n.code,{children:"Bar"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl MyTrait for Field {\n    type Foo = i32;\n\n    let Bar: u32 = 11;\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"Since associated constants can also be used in a type position, its values are limited to only other\nexpression kinds allowed in numeric generics."}),"\n",(0,r.jsx)(n.p,{children:"When writing a trait constraint, you can specify all associated types and constants explicitly if\nyou wish:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn foo<T>(x: T) where T: MyTrait<Foo = i32, Bar = 11> {\n    ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Or you can also elide them since there should only be one ",(0,r.jsx)(n.code,{children:"Foo"})," and ",(0,r.jsx)(n.code,{children:"Bar"})," for a given implementation\nof ",(0,r.jsx)(n.code,{children:"MyTrait"})," for a type:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn foo<T>(x: T) where T: MyTrait {\n    ...\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["If you elide associated types, you can still refer to them via the type as trait syntax ",(0,r.jsx)(n.code,{children:"<T as MyTrait>"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"fn foo<T>(x: T) where\n    T: MyTrait,\n    <T as MyTrait>::Foo: Default + Eq\n{\n    let foo_value: <T as MyTrait>::Foo = Default::default();\n    assert_eq(foo_value, foo_value);\n}\n"})}),"\n",(0,r.jsxs)(n.h2,{id:"trait-methods-with-no-self",children:["Trait Methods With No ",(0,r.jsx)(n.code,{children:"self"})]}),"\n",(0,r.jsxs)(n.p,{children:["A trait can contain any number of methods, each of which have access to the ",(0,r.jsx)(n.code,{children:"Self"}
1)," type which represents each type\nthat eventually implements the trait. Similarly, the ",(0,r.jsx)(n.code,{children:"self"})," variable is available as well but is not required to be used.\nFor example, we can define a trait to create a default value for a type. This trait will need to return the ",(0,r.jsx)(n.code,{children:"Self"})," type\nbut doesn't need to take any parameters:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Default {\n    fn default() -> Self;\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"Implementing this trait can be done similarly to any other trait:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl Default for Field {\n    fn default() -> Field {\n        0\n    }\n}\n\nstruct MyType {}\n\nimpl Default for MyType {\n    fn default() -> Field {\n        MyType {}\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["However, since there is no ",(0,r.jsx)(n.code,{children:"self"})," parameter, we cannot call it via the method call syntax ",(0,r.jsx)(n.code,{children:"object.method()"}),".\nInstead, we'll need to refer to the function directly. This can be done either by referring to the\nspecific impl ",(0,r.jsx)(n.code,{children:"MyType::default()"})," or referring to the trait itself ",(0,r.jsx)(n.code,{children:"Default::default()"}),". In the later\ncase, type inference determines the impl that is selected."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"let my_struct = MyStruct::default();\n\nlet x: u64 = Default::default();\nlet result = x + Default::default();\n"})}),"\n",(0,r.jsx)(n.h2,{id:"default-method-implementations",children:"Default Method Implementations"}),"\n",(0,r.jsxs)(n.p,{children:["A trait can also have default implementations of its methods by giving a body to the desired functions.\nNote that this body must be valid for all types that may implement the trait. As a result, the only\nvalid operations on ",(0,r.jsx)(n.code,{children:"self"})," will be operations valid for any type or other operations on the trait itself."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Numeric {\n    fn add(self, other: Self) -> Self;\n\n    // Default implementation of double is (self + self)\n    fn double(self) -> Self {\n        self.add(self)\n    }\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"When implementing a trait with default functions, a type may choose to implement only the required functions:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl Numeric for Field {\n    fn add(self, other: Field) -> Field {\n        self + other\n    }\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"Or it may implement the optional methods as well:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"impl Numeric for u32 {\n    fn add(self, other: u32) -> u32 {\n        self + other\n    }\n\n    fn double(self) -> u32 {\n        self * 2\n    }\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"impl-specialization",children:"Impl Specialization"}),"\n",(0,r.jsx)(n.p,{children:"When implementing traits for a generic type it is possible to implement the trait for only a certain combination\nof generics. This can be either as an optimization or because those specific generics are required to implement the trait."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Sub {\n    fn sub(self, other: Self) -> Self;\n}\n\nstruct NonZero<T> {\n    value: T,\n}\n\nimpl Sub for NonZero<Field> {\n    fn sub(self, other: Self) -> Self {\n        let value = self.value - other.value;\n        assert(value != 0);\n        NonZero { value }\n    }\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"overlapping-implementations",children:"Overlapping Implementations"}),"\n",(0,r.jsxs)(n.p,{children:["Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous.\nThis means if a trait ",(0,r.jsx)(n.code,{children:"Foo"})," is already implemented\nby a type ",(0,r.jsx)(n.code,{children:"Bar<T>"})," for all ",(0,r.jsx)(n.code,{children:"T"}),", then we cannot also have a separate impl for ",(0,r.jsx)(n.code,{children:"Bar<Field>"})," (or any other\ntype argument). Similarly, if there is an impl for all ",(0,r.jsx)(n.code,{children:"T"})," such as ",(0,r.jsx)(n.code,{children:"impl<T> Debug for T"}),", we cannot create\nany more impls to ",(0,r.jsx)(n.code,{children:"Debug"})," for other types since it would be ambiguous which impl to choose for any given\nmethod call."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Trait {}\n\n// Previous impl defined here\nimpl<A, B> Trait for (A, B) {}\n\n// error: Impl for type `(Field, Field)` overlaps with existing impl\nimpl Trait for (Field, Field) {}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"trait-coherence",children:"Trait Coherence"}),"\n",(0,r.jsx)(n.p,{children:"Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create\nimpls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same\nprogram."}),"\n",(0,r.jsx)(n.p,{children:"The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared\nin the crate the impl is in."}),"\n",(0,r.jsxs)(n.p,{children:["In practice this often comes up when using types provided by libraries. If a library provides a type ",(0,r.jsx)(n.code,{children:"Foo"})," that does\nnot implement a trait in the standard library such as ",(0,r.jsx)(n.code,{children:"Default"}
1),", you may not ",(0,r.jsx)(n.code,{children:"impl Default for Foo"})," in your own crate.\nWhile restrictive, this prevents later issues or silent changes in the program if the ",(0,r.jsx)(n.code,{children:"Foo"})," library later added its\nown impl for ",(0,r.jsx)(n.code,{children:"Default"}),". If you are a user of the ",(0,r.jsx)(n.code,{children:"Foo"})," library in this scenario and need a trait not implemented by the\nlibrary your choices are to either submit a patch to the library or use the newtype pattern."]}),"\n",(0,r.jsx)(n.h3,{id:"the-newtype-pattern",children:"The Newtype Pattern"}),"\n",(0,r.jsxs)(n.p,{children:["The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type\nthat we cannot create ",(0,r.jsx)(n.code,{children:"impl"}),"s for. Since the new wrapper type is defined in our current crate, we can create\nimpls for any trait we need on it."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"struct Wrapper {\n    foo: some_library::Foo,\n}\n\nimpl Default for Wrapper {\n    fn default() -> Wrapper {\n        Wrapper {\n            foo: some_library::Foo::new(),\n        }\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Since we have an impl for our own type, the behavior of this code will not change even if ",(0,r.jsx)(n.code,{children:"some_library"})," is updated\nto provide its own ",(0,r.jsx)(n.code,{children:"impl Default for Foo"}),". The downside of this pattern is that it requires extra wrapping and\nunwrapping of values when converting to and from the ",(0,r.jsx)(n.code,{children:"Wrapper"})," and ",(0,r.jsx)(n.code,{children:"Foo"})," types."]}),"\n",(0,r.jsx)(n.h3,{id:"trait-inheritance",children:"Trait Inheritance"}),"\n",(0,r.jsx)(n.p,{children:'Sometimes, you might need one trait to use another trait\u2019s functionality (like "inheritance" in some other languages). In this case, you can specify this relationship by listing any child traits after the parent trait\'s name and a colon. Now, whenever the parent trait is implemented it will require the child traits to be implemented as well. A parent trait is also called a "super trait."'}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Person {\n    fn name(self) -> String;\n}\n\n// Person is a supertrait of Student.\n// Implementing Student requires you to also impl Person.\ntrait Student: Person {\n    fn university(self) -> String;\n}\n\ntrait Programmer {\n    fn fav_language(self) -> String;\n}\n\n// CompSciStudent (computer science student) is a subtrait of both Programmer\n// and Student. Implementing CompSciStudent requires you to impl both supertraits.\ntrait CompSciStudent: Programmer + Student {\n    fn git_username(self) -> String;\n}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"trait-aliases",children:"Trait Aliases"}),"\n",(0,r.jsxs)(n.p,{children:["Similar to the proposed Rust feature for ",(0,r.jsx)(n.a,{href:"https://github.com/rust-lang/rust/blob/4d215e2426d52ca8d1af166d5f6b5e172afbff67/src/doc/unstable-book/src/language-features/trait-alias.md",children:"trait aliases"}),",\nNoir supports aliasing one or more traits and using those aliases wherever\ntraits would normally be used."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Foo {\n    fn foo(self) -> Self;\n}\n\ntrait Bar {\n    fn bar(self) -> Self;\n}\n\n// Equivalent to:\n// trait Baz: Foo + Bar {}\n//\n// impl<T> Baz for T where T: Foo + Bar {}\ntrait Baz = Foo + Bar;\n\n// We can use `Baz` to refer to `Foo + Bar`\nfn baz<T>(x: T) -> T where T: Baz {\n    x.foo().bar()\n}\n"})}),"\n",(0,r.jsx)(n.h4,{id:"generic-trait-aliases",children:"Generic Trait Aliases"}),"\n",(0,r.jsx)(n.p,{children:"Trait aliases can also be generic by placing the generic arguments after the\ntrait name. These generics are in scope of every item within the trait alias."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Foo {\n    fn foo(self) -> Self;\n}\n\ntrait Bar<T> {\n    fn bar(self) -> T;\n}\n\n// Equivalent to:\n// trait Baz<T>: Foo + Bar<T> {}\n//\n// impl<T, U> Baz<T> for U where U: Foo + Bar<T> {}\ntrait Baz<T> = Foo + Bar<T>;\n"})}),"\n",(0,r.jsx)(n.h4,{id:"trait-alias-where-clauses",children:"Trait Alias Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["Trait aliases support where clauses to add trait constraints to any of their\ngeneric arguments, e.g. ensuring ",(0,r.jsx)(n.code,{children:"T: Baz"})," for a trait alias ",(0,r.jsx)(n.code,{children:"Qux<T>"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"trait Foo {\n    fn foo(self) -> Self;\n}\n\ntrait Bar<T> {\n    fn bar(self) -> T;\n}\n\ntrait Baz {\n    fn baz(self) -> bool;\n}\n\n// Equivalent to:\n// trait Qux<T>: Foo + Bar<T> where T: Baz {}\n//\n// impl<T, U> Qux<T> for U where\n//     U: Foo + Bar<T>,\n//     T: Baz,\n// {}\ntrait Qux<T> = Foo + Bar<T> where T: Baz;\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note that while trait aliases support where clauses,\nthe equivalent traits can fail due to ",(0,r.jsx)(n.a,{href:"https://github.com/noir-lang/noir/issues/6467",children:"#6467"})]}),"\n",(0,r.jsx)(n.h3,{id:"visibility",children:"Visibility"}),"\n",(0,r.jsxs)(n.p,{children:["By default, like functions, traits and trait aliases are private to the module\nthey exist in. You can use ",(0,r.jsx)(n.code,{children:"pub"})," to make the trait public or ",(0,r.jsx)(n.code,{children:"pub(crate)"})," to make\nit public to just its crate:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-rust",children:"// This trait is now public\npub trait Trait {}\n\n// This trait alias is now public\npub trait Baz = Foo + Bar;\n"})}),"\n",(0,r.jsx)(n.p,{children:"Trait methods have the same visibility as the trait they are in."})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>l});var a=t(96540);const r={},i=a.createContext(r);function s(e){const n=a.useContext(i);return a.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),a.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.