@@ -637,60 +637,55 @@ conditions on the type argument. For example: `Array(T)` might implement
637
637
638
638
## Interface type parameters and associated types
639
639
640
- Imagine an interface defining a container. Different containers will contain
641
- different types of values, and the container API will have to refer to that
642
- "element type" when defining the signature of methods like "insert" or "find".
643
- If that element type is a parameter (input) to the interface type, we say it is
644
- an _ interface type parameter _ ; if it is an output, we say it is an _ associated
645
- type _ . An associated type is a kind of [ associated entity ] ( # associated-entity ) .
646
-
647
- Interface type parameter example :
640
+ _ Interface type parameters _ and _ associated types _ are both ways of allowing the
641
+ types in function signatures in an interface to vary. For example, different
642
+ [ stacks ] ( < https://en.wikipedia.org/wiki/Stack_(abstract_data_type) > ) will have
643
+ different element types. That element type would be used as the parameter type
644
+ of the ` Push ` function and the return type of the ` Pop ` function. As
645
+ [ in Rust ] ( https://rust-lang.github.io/rfcs/0195- associated-items.html#clearer-trait-matching ) ,
646
+ we can distinguish these by whether they are input parameters or output
647
+ parameters :
648
648
649
- ```
650
- interface StackTP(ElementType:! Type)
651
- fn Push[addr me: Self*](value: ElementType);
652
- fn Pop[addr me: Self*]() -> ElementType;
653
- }
654
- ```
649
+ - An interface type parameter is a parameter or input to the interface type.
650
+ That means they must be specified before an implementation of the interface
651
+ may be determined.
652
+ - In contrast, associated types are outputs. This means that they are
653
+ determined by the implementation, and need not be specified in a type
654
+ constraint.
655
655
656
- Associated type example:
656
+ Functions using an interface as a constraint need not specify the value of its
657
+ associated types. An associated type is a kind of
658
+ [ associated entity] ( #associated-entity ) .
657
659
658
660
```
659
- interface StackAT {
661
+ // Stack using associated types
662
+ interface Stack {
660
663
let ElementType:! Type;
661
664
fn Push[addr me: Self*](value: ElementType);
662
665
fn Pop[addr me: Self*]() -> ElementType;
663
666
}
664
- ```
665
-
666
- Associated types are particularly called for when the implementation controls
667
- the type, not the caller. For example, the iterator type for a container is
668
- specific to the container and not something you would expect a user of the
669
- interface to specify.
670
667
671
- ```
672
- interface Iterator { ... }
673
- interface Container {
674
- // This does not make sense as an parameter to the container interface,
675
- // since this type is determined from the container type.
676
- let IteratorType:! Iterator;
677
- ...
678
- fn Insert[addr me: Self*](position: IteratorType, value: ElementType);
668
+ // Works on any type implementing `Stack`. Return type
669
+ // is determined by the type's implementation of `Stack`.
670
+ fn PeekAtTopOfStack[T: Stack](s: T*) -> T.ElementType {
671
+ let ret: T.ElementType = s->Pop();
672
+ s->Push(ret);
673
+ return ret;
679
674
}
680
- class ListIterator(ElementType:! Type) {
681
- ...
682
- impl as Iterator;
683
- }
684
- class List(ElementType:! Type) {
685
- // Iterator type is determined by the container type.
686
- impl as Container where .IteratorType = ListIterator(ElementType) {
687
- fn Insert[addr me: Self*](position: IteratorType, value: ElementType) {
688
- ...
689
- }
690
- }
675
+
676
+ class Fruit;
677
+ class FruitStack {
678
+ // Implement `Stack` for `FruitStack`
679
+ // with `ElementType` set to `Fruit`.
680
+ impl as Stack where .ElementType == Fruit { ... }
691
681
}
692
682
```
693
683
684
+ Associated types are particularly called for when the implementation of the
685
+ interface determines the type, not the caller. For example, the iterator type
686
+ for a container is specific to the container and not something you would expect
687
+ a user of the interface to specify.
688
+
694
689
If you have an interface with type parameters, a type can have multiple impls
695
690
for different combinations of type parameters. As a result, type parameters may
696
691
not be deduced in a function call. However, if the interface parameters are
@@ -701,7 +696,7 @@ For example, we might have an interface that says how to perform addition with
701
696
another type:
702
697
703
698
```
704
- interface Addable (T:! Type) {
699
+ interface AddWith (T:! Type) {
705
700
let ResultType:! Type;
706
701
fn Add[me: Self](rhs: T) -> ResultType;
707
702
}
@@ -710,31 +705,31 @@ interface Addable(T:! Type) {
710
705
An ` i32 ` value might support addition with ` i32 ` , ` u16 ` , and ` f64 ` values.
711
706
712
707
```
713
- impl i32 as Addable (i32) where .ResultType = i32 { ... }
714
- impl i32 as Addable (u16) where .ResultType = i32 { ... }
715
- impl i32 as Addable (f64) where .ResultType = f64 { ... }
708
+ impl i32 as AddWith (i32) where .ResultType = i32 { ... }
709
+ impl i32 as AddWith (u16) where .ResultType = i32 { ... }
710
+ impl i32 as AddWith (f64) where .ResultType = f64 { ... }
716
711
```
717
712
718
- To write a generic function requiring a parameter to be ` Addable ` , there needs
713
+ To write a generic function requiring a parameter to be ` AddWith ` , there needs
719
714
to be some way to determine the type to add to:
720
715
721
716
```
722
717
// ✅ This is allowed, since the value of `T` is determined by the
723
718
// `y` parameter.
724
- fn DoAdd[T:! Type, U:! Addable (T)](x: U, y: T) -> U.ResultType {
719
+ fn DoAdd[T:! Type, U:! AddWith (T)](x: U, y: T) -> U.ResultType {
725
720
return x.Add(y);
726
721
}
727
722
728
723
// ❌ This is forbidden, can't uniquely determine `T`.
729
- fn CompileError[T:! Type, U:! Addable (T)](x: U) -> T;
724
+ fn CompileError[T:! Type, U:! AddWith (T)](x: U) -> T;
730
725
```
731
726
732
727
Once the interface parameter can be determined, that determines the values for
733
728
associated types, such as ` ResultType ` in the example. As always, calls with
734
729
types for which no implementation exists will be rejected at the call site:
735
730
736
731
```
737
- // ❌ This is forbidden, no implementation of `Addable (Orange)`
732
+ // ❌ This is forbidden, no implementation of `AddWith (Orange)`
738
733
// for `Apple`.
739
734
DoAdd(apple, orange);
740
735
```
0 commit comments