|
1 | 1 | = Impl aliases |
2 | 2 |
|
3 | | -This section is a work in progress. |
| 3 | +Impl aliases provide alternative names for existing impls. |
| 4 | +They do not introduce new impls; instead, they refer to an existing implementation, |
| 5 | +possibly with concrete generic arguments. |
4 | 6 |
|
5 | | -You are very welcome to contribute to this documentation by |
6 | | -link:https://github.com/starkware-libs/cairo/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22[submitting a pull request]. |
| 7 | +Impl aliases are useful for: |
| 8 | + |
| 9 | +- Providing shorter or more descriptive names for complex impls. |
| 10 | +- Re-exporting impls from other modules. |
| 11 | +- Fixing some generic arguments of an impl while keeping others generic. |
| 12 | +
|
| 13 | +See also xref:aliases.adoc[Type and impl aliases], |
| 14 | +xref:traits.adoc[Traits and impls] and xref:generics.adoc[Generics]. |
| 15 | + |
| 16 | +== Syntax |
| 17 | + |
| 18 | +An impl alias has the following form: |
| 19 | + |
| 20 | +[source,cairo] |
| 21 | +---- |
| 22 | +impl ImplAliasName<GenericParams> = path::to::Impl<GenericArgs>; |
| 23 | +---- |
| 24 | + |
| 25 | +Where: |
| 26 | + |
| 27 | +- `ImplAliasName` is the new name of the impl. |
| 28 | +- `GenericParams` are the generic parameters introduced by the alias (optional). |
| 29 | +- `path::to::Impl` is a path to an existing impl or impl alias. |
| 30 | +- `GenericArgs` are the concrete generic arguments passed to that impl (optional). |
| 31 | + |
| 32 | +The path on the right-hand side must resolve to an impl (or another impl alias). |
| 33 | +If it does not, the compiler reports an error. |
| 34 | + |
| 35 | +== Basic example |
| 36 | + |
| 37 | +The following example defines a trait and an impl, and then introduces an impl alias |
| 38 | +to give this implementation a shorter name: |
| 39 | + |
| 40 | +[source,cairo] |
| 41 | +---- |
| 42 | +trait Pow<T> { |
| 43 | + fn pow(base: T, exp: u32) -> T; |
| 44 | +} |
| 45 | +
|
| 46 | +impl AnyAlgebraPow<T, impl AlgImpl: Algebra<T>> of Pow<T> { |
| 47 | + fn pow(base: T, exp: u32) -> T { |
| 48 | + // Implementation details. |
| 49 | + base |
| 50 | + } |
| 51 | +} |
| 52 | +
|
| 53 | +// Impl alias for Pow of felt252. |
| 54 | +impl FeltPow = AnyAlgebraPow<felt252, FeltAlgebra>; |
| 55 | +
|
| 56 | +fn main() { |
| 57 | + // Call through the trait name. |
| 58 | + let x = Pow::pow(5, 3); |
| 59 | +
|
| 60 | + // Call through the impl alias name. |
| 61 | + let y = FeltPow::pow(5, 3); |
| 62 | +} |
| 63 | +---- |
| 64 | + |
| 65 | +Here `FeltPow` is just another name for the concrete impl |
| 66 | +`AnyAlgebraPow<felt252, FeltAlgebra>`. No new impl is created. |
| 67 | + |
| 68 | +== Generic impl aliases |
| 69 | + |
| 70 | +Impl aliases can themselves be generic. |
| 71 | +This allows fixing some of the generic arguments of an existing impl |
| 72 | +while leaving others as parameters of the alias. |
| 73 | + |
| 74 | +[source,cairo] |
| 75 | +---- |
| 76 | +trait MyTrait<T> { |
| 77 | + fn foo(x: T) -> usize; |
| 78 | +} |
| 79 | +
|
| 80 | +mod inner { |
| 81 | + impl MyImpl<T> of MyTrait<Option<T>> { |
| 82 | + fn foo(x: Option<T>) -> usize { |
| 83 | + 0_usize |
| 84 | + } |
| 85 | + } |
| 86 | +} |
| 87 | +
|
| 88 | +// Fix the outer type to `Box<T>` but keep `T` generic. |
| 89 | +impl MyImplAlias<T> = inner::MyImpl<Box<T>>; |
| 90 | +
|
| 91 | +fn use_alias(x: Box<usize>) -> usize { |
| 92 | + MyTrait::foo(x) |
| 93 | +} |
| 94 | +---- |
| 95 | + |
| 96 | +In this example, `MyImplAlias<T>` is an alias for a family of impls |
| 97 | +`inner::MyImpl<Box<T>>`. The generic parameter `T` of the alias is |
| 98 | +substituted into the generic parameter of the underlying impl. |
| 99 | + |
| 100 | +== Chaining impl aliases |
| 101 | + |
| 102 | +An impl alias can refer to another impl alias. |
| 103 | +The compiler resolves such chains transitively until it reaches the |
| 104 | +underlying concrete impl. |
| 105 | + |
| 106 | +[source,cairo] |
| 107 | +---- |
| 108 | +trait Trait1<T> { |
| 109 | + fn func1(value: T); |
| 110 | +} |
| 111 | +
|
| 112 | +trait Trait2<T> { |
| 113 | + fn func2(value: T); |
| 114 | +} |
| 115 | +
|
| 116 | +mod impls { |
| 117 | + impl Impl1<T, +Drop<T>> of super::Trait1<T> { |
| 118 | + fn func1(value: T) {} |
| 119 | + } |
| 120 | +
|
| 121 | + // Public alias for a concrete impl of Trait1<felt252>. |
| 122 | + pub impl ImplAlias1 = Impl1<felt252>; |
| 123 | +
|
| 124 | + impl Impl2<T, +Drop<T>> of super::Trait2<T> { |
| 125 | + fn func2(value: T) {} |
| 126 | + } |
| 127 | +
|
| 128 | + // Public alias for a concrete impl of Trait2<felt252>. |
| 129 | + pub impl ImplAlias2 = Impl2<felt252>; |
| 130 | +} |
| 131 | +
|
| 132 | +use impls::ImplAlias1; |
| 133 | +
|
| 134 | +// A second-level alias that refers to an impl alias from another module. |
| 135 | +impl Impl2Alias = impls::ImplAlias2; |
| 136 | +---- |
| 137 | + |
| 138 | +Both `ImplAlias1` and `Impl2Alias` are names for existing impls. |
| 139 | +They can be used wherever an impl name is expected, for example |
| 140 | +in generic parameters or when calling trait methods. |
| 141 | + |
| 142 | +== Using impl aliases |
| 143 | + |
| 144 | +Impl aliases can be used anywhere a named impl can be used: |
| 145 | + |
| 146 | +- When calling trait methods through an impl name. |
| 147 | +- As impl generic arguments in generic functions, structs, enums, and so on. |
| 148 | + |
| 149 | +For example: |
| 150 | + |
| 151 | +[source,cairo] |
| 152 | +---- |
| 153 | +trait Display<T> { |
| 154 | + fn display(x: T) -> Array<u8>; |
| 155 | +} |
| 156 | +
|
| 157 | +impl DisplayFelt of Display<felt252> { |
| 158 | + fn display(x: felt252) -> Array<u8> { |
| 159 | + // ... |
| 160 | + ArrayTrait::new() |
| 161 | + } |
| 162 | +} |
| 163 | +
|
| 164 | +// Provide a shorter name for the concrete impl. |
| 165 | +impl FeltDisplay = DisplayFelt; |
| 166 | +
|
| 167 | +fn print_value<T, impl D: Display<T>>(value: T) { |
| 168 | + let bytes = D::display(value); |
| 169 | + // ... |
| 170 | +} |
| 171 | +
|
| 172 | +fn main() { |
| 173 | + // Use the impl alias as a concrete impl argument. |
| 174 | + print_value::<felt252, FeltDisplay>(5); |
| 175 | +} |
| 176 | +---- |
| 177 | + |
| 178 | +== Errors and limitations |
| 179 | + |
| 180 | +When working with impl aliases, the compiler enforces several rules: |
| 181 | + |
| 182 | +- The right-hand side of an impl alias must resolve to an impl or another impl alias. |
| 183 | + If it resolves to anything else, a compilation error is reported. |
| 184 | +- Cyclic impl aliases (where aliases form a cycle through their right-hand sides) |
| 185 | + are rejected by the compiler. |
| 186 | + |
| 187 | +Apart from these restrictions, impl aliases behave like their underlying impls |
| 188 | +in name resolution and generic argument handling. |
0 commit comments