Update design docs with syntax changes from #2760 (#2866)

This includes:

- Syntax changes from this chart:

| Before                          | After                                   |
| ------------------------------- | --------------------------------------- |
| `class D extends B { ... }`     | `class D { extend base: B; ... }`       |
| `external impl C as Sub;`       | `impl C as Sub;`                        |
| `class C { impl as Sortable; }` | `class C { extend impl as Sortable; }`  |
| `adapter A for C { ... }`       | `class A { adapt C; ... }`              |
| `adapter A extends C { ... }`   | `class A { extend adapt C; ... }`       |
| `interface I { impl as J; }`    | `interface I { require Self impls J; }` |
| `interface I { extends J; }`    | `interface I { extend J; }`             |

- Dropping the syntax for conditionally implemented internal interfaces.

This does not include:

- terminology changes from #2760 ("internal" and "external")
- changes to code, such as explorer, toolchain, language grammars, or other tooling
This commit is contained in:
josh11b
2023-06-16 14:22:29 -07:00
committed by GitHub
parent e2b1511a0d
commit 2ae8117d62
14 changed files with 578 additions and 508 deletions
+26 -17
View File
@@ -1724,9 +1724,16 @@ Classes may only extend a single class. Carbon only supports single inheritance,
and will use mixins instead of multiple inheritance.
```carbon
base class MiddleDerived extends MyBaseClass { ... }
class FinalDerived extends MiddleDerived { ... }
// ❌ Forbidden: class Illegal extends FinalDerived { ... }
base class MiddleDerived {
extend base: MyBaseClass;
...
}
class FinalDerived {
extend base: MiddleDerived;
...
}
// ❌ Forbidden: class Illegal { extend base: FinalDerived; ... }
// may not extend `FinalDerived` since not declared `base` or `abstract`.
```
A base class may define
@@ -1761,7 +1768,8 @@ For purposes of construction, a derived class acts like its first field is
called `base` with the type of its immediate base class.
```carbon
class MyDerivedType extends MyBaseType {
class MyDerivedType {
extend base: MyBaseType;
fn Make() -> MyDerivedType {
return {.base = MyBaseType.Make(), .derived_field = 7};
}
@@ -1785,7 +1793,8 @@ abstract class AbstractClass {
// ❌ Error: can't instantiate abstract class
var abc: AbstractClass = ...;
class DerivedFromAbstract extends AbstractClass {
class DerivedFromAbstract {
extend base: AbstractClass;
fn Make() -> Self {
// AbstractClass.Make() returns a
// `partial AbstractClass` that can be used as
@@ -2398,8 +2407,8 @@ or [named constraint](generics/details.md#named-constraints), possibly renamed:
```carbon
class ContactInfo {
external impl as Printable;
external impl as ToPrinterDevice;
impl as Printable;
impl as ToPrinterDevice;
alias PrintToScreen = Printable.Print;
alias PrintToPrinter = ToPrinterDevice.Print;
...
@@ -2667,7 +2676,7 @@ sufficient.
class Circle {
var radius: f32;
impl as Printable {
extend impl as Printable {
fn Print[self: Self]() {
Carbon.Print("Circle with radius: {0}", self.radius);
}
@@ -2773,14 +2782,14 @@ values for the `ElementType` member of the interface using a `where` clause:
```carbon
class IntStack {
impl as StackInterface where .ElementType = i32 {
extend impl as StackInterface where .ElementType = i32 {
fn Push[addr self: Self*](value: i32);
// ...
}
}
class FruitStack {
impl as StackInterface where .ElementType = Fruit {
extend impl as StackInterface where .ElementType = Fruit {
fn Push[addr self: Self*](value: Fruit);
// ...
}
@@ -2886,12 +2895,12 @@ An `impl` declaration may be parameterized by adding `forall [`_generic
parameter list_`]` after the `impl` keyword introducer, as in:
```carbon
external impl forall [T:! Printable] Vector(T) as Printable;
external impl forall [Key:! Hashable, Value:! type]
impl forall [T:! Printable] Vector(T) as Printable;
impl forall [Key:! Hashable, Value:! type]
HashMap(Key, Value) as Has(Key);
external impl forall [T:! Ordered] T as PartiallyOrdered;
external impl forall [T:! ImplicitAs(i32)] BigInt as AddWith(T);
external impl forall [U:! type, T:! As(U)]
impl forall [T:! Ordered] T as PartiallyOrdered;
impl forall [T:! ImplicitAs(i32)] BigInt as AddWith(T);
impl forall [U:! type, T:! As(U)]
Optional(T) as As(Optional(U));
```
@@ -3014,7 +3023,7 @@ to type `T` and the second argument to type `U`, add the `like` keyword to both
types in the `impl` declaration, as in:
```carbon
external impl like T as AddWith(like U) where .Result = V {
impl like T as AddWith(like U) where .Result = V {
// `Self` is `T` here
fn Op[self: Self](other: U) -> V { ... }
}
@@ -3024,7 +3033,7 @@ When the operand types and result type are all the same, this is equivalent to
implementing the `Add` interface:
```carbon
external impl T as Add {
impl T as Add {
fn Op[self: Self](other: Self) -> Self { ... }
}
```
+11 -11
View File
@@ -177,7 +177,7 @@ provided for built-in types as necessary to give the semantics described above.
interface AssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint Assign { extends AssignWith(Self); }
constraint Assign { extend AssignWith(Self); }
```
Given `var x: T` and `y: U`:
@@ -191,7 +191,7 @@ Given `var x: T` and `y: U`:
interface AddAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint AddAssign { extends AddAssignWith(Self); }
constraint AddAssign { extend AddAssignWith(Self); }
```
```
@@ -199,7 +199,7 @@ constraint AddAssign { extends AddAssignWith(Self); }
interface SubAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint SubAssign { extends SubAssignWith(Self); }
constraint SubAssign { extend SubAssignWith(Self); }
```
```
@@ -207,7 +207,7 @@ constraint SubAssign { extends SubAssignWith(Self); }
interface MulAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint MulAssign { extends MulAssignWith(Self); }
constraint MulAssign { extend MulAssignWith(Self); }
```
```
@@ -215,7 +215,7 @@ constraint MulAssign { extends MulAssignWith(Self); }
interface DivAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint DivAssign { extends DivAssignWith(Self); }
constraint DivAssign { extend DivAssignWith(Self); }
```
```
@@ -223,7 +223,7 @@ constraint DivAssign { extends DivAssignWith(Self); }
interface ModAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint ModAssign { extends ModAssignWith(Self); }
constraint ModAssign { extend ModAssignWith(Self); }
```
```
@@ -250,7 +250,7 @@ Given `var x: T` and `y: U`:
interface BitAndAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint BitAndAssign { extends BitAndAssignWith(Self); }
constraint BitAndAssign { extend BitAndAssignWith(Self); }
```
```
@@ -258,7 +258,7 @@ constraint BitAndAssign { extends BitAndAssignWith(Self); }
interface BitOrAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint BitOrAssign { extends BitOrAssignWith(Self); }
constraint BitOrAssign { extend BitOrAssignWith(Self); }
```
```
@@ -266,7 +266,7 @@ constraint BitOrAssign { extends BitOrAssignWith(Self); }
interface BitXorAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint BitXorAssign { extends BitXorAssignWith(Self); }
constraint BitXorAssign { extend BitXorAssignWith(Self); }
```
```
@@ -274,7 +274,7 @@ constraint BitXorAssign { extends BitXorAssignWith(Self); }
interface LeftShiftAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint LeftShiftAssign { extends LeftShiftAssignWith(Self); }
constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); }
```
```
@@ -282,7 +282,7 @@ constraint LeftShiftAssign { extends LeftShiftAssignWith(Self); }
interface RightShiftAssignWith(U:! type) {
fn Op[addr self: Self*](other: U);
}
constraint RightShiftAssign { extends RightShiftAssignWith(Self); }
constraint RightShiftAssign { extend RightShiftAssignWith(Self); }
```
Given `var x: T` and `y: U`:
+45 -21
View File
@@ -684,7 +684,6 @@ The declarations for nominal class types will have:
- an optional `abstract` or `base` prefix
- `class` introducer
- the name of the class
- an optional `extends` followed by the name of the immediate base class
- `{`, an open curly brace
- a sequence of declarations
- `}`, a close curly brace
@@ -712,9 +711,9 @@ determined at compile time.
To support circular references between class types, we allow
[forward declaration](https://en.wikipedia.org/wiki/Forward_declaration) of
types. Forward declarations end with semicolon `;` after the name of the class,
instead of any `extends` clause and the block of declarations in curly braces
`{`...`}`. A type that is forward declared is considered incomplete until the
end of a definition with the same name.
instead of the block of declarations in curly braces `{`...`}`. A type that is
forward declared is considered incomplete until the end of a definition with the
same name.
```
// Forward declaration of `GraphNode`.
@@ -1132,9 +1131,16 @@ base class MyBaseClass { ... }
A _base class_ may be _extended_ to get a _derived class_:
```
base class MiddleDerived extends MyBaseClass { ... }
class FinalDerived extends MiddleDerived { ... }
// ❌ Forbidden: class Illegal extends FinalDerived { ... }
base class MiddleDerived {
extend base: MyBaseClass;
...
}
class FinalDerived {
extend base: MiddleDerived;
...
}
// ❌ Forbidden: class Illegal { extend base: FinalDerived; ... }
// may not extend `FinalDerived` since not declared `base` or `abstract`.
```
An _[abstract class](https://en.wikipedia.org/wiki/Abstract_type)_ or _abstract
@@ -1218,7 +1224,7 @@ There are three virtual override keywords:
doesn't match the base class. We intentionally use the same keyword here as
for implementing interfaces, to emphasize that they are similar operations.
| Keyword on<br />method in `C` | Allowed in<br />`abstract class C` | Allowed in<br />`base class C` | Allowed in<br />final `class C` | in `B` where<br />`C extends B` | in `D` where<br />`D extends C` |
| Keyword on<br />method in `C` | Allowed in<br />`abstract class C` | Allowed in<br />`base class C` | Allowed in<br />final `class C` | in `B` where<br />`C` extends `B` | in `D` where<br />`D` extends `C` |
| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `virtual` | ✅ | ✅ | ❌ | _not present_ | `abstract`<br />`impl`<br />_not mentioned_ |
| `abstract` | ✅ | ❌ | ❌ | _not present_<br />`virtual`<br />`abstract`<br />`impl` | `abstract`<br />`impl`<br />_may not be<br />mentioned if<br />`D` is not final_ |
@@ -1252,7 +1258,10 @@ base class Extensible { ... }
// Can be replaced by:
abstract class ExtensibleBase { ... }
class ExactlyExtensible extends ExtensibleBase { ... }
class ExactlyExtensible {
extend base: ExtensibleBase;
...
}
```
#### `Self` refers to the current type
@@ -1269,7 +1278,8 @@ base class B1 {
// virtual fn F[self: B1](x: B1) -> B1;
}
class D1 extends B1 {
class D1 {
extend base: B1;
// ❌ Illegal:
// impl fn F[self: Self](x: Self) -> Self;
// since that would mean the same thing as:
@@ -1294,7 +1304,8 @@ base class B2 {
// virtual fn Clone[self: B2]() -> B2*;
}
class D2 extends B2 {
class D2 {
extend base: B2;
// ✅ Allowed
impl fn Clone[self: Self]() -> Self*;
// Means the same thing as:
@@ -1320,7 +1331,8 @@ type, this time with a `.base` member to initialize the members of the immediate
base type.
```
class MyDerivedType extends MyBaseType {
class MyDerivedType {
extend base: MyBaseType;
fn Create() -> MyDerivedType {
return {.base = MyBaseType.Create(), .derived_field = ...};
}
@@ -1455,7 +1467,8 @@ abstract class MyAbstractClass {
}
// Base class returns a partial type
base class Derived extends MyAbstractClass {
base class Derived {
extend base: MyAbstractClass;
protected fn Create() -> partial Self {
return {.base = MyAbstractClass.Create(), .derived_field = ...};
}
@@ -1467,7 +1480,8 @@ base class MyBaseClass {
}
// Base class returns a full type
base class ExtensibleDerived extends MyBaseClass {
base class ExtensibleDerived {
extend base: MyBaseClass;
fn Create() -> Self {
return {.base = MyBaseClass.Create(), .derived_field = ...};
}
@@ -1478,7 +1492,8 @@ base class ExtensibleDerived extends MyBaseClass {
And final classes will return a type that does not use the partial facet:
```
class FinalDerived extends MiddleDerived {
class FinalDerived {
extend base: MiddleDerived;
fn Create() -> Self {
return {.base = MiddleDerived.Create(), .derived_field = ...};
}
@@ -1572,7 +1587,8 @@ base class MyBaseClass {
virtual destructor [addr self: Self*] { ... }
}
class MyDerivedClass extends MyBaseClass {
class MyDerivedClass {
extend base: MyBaseClass;
impl destructor [addr self: Self*] { ... }
}
```
@@ -1633,7 +1649,8 @@ function expecting a `Deletable` type, use the `UnsafeAllowDelete`
[type adapter](/docs/design/generics/details.md#adapting-types).
```
adapter UnsafeAllowDelete(T:! Concrete) extends T {
class UnsafeAllowDelete(T:! Concrete) {
extend adapt T;
impl as Deletable {}
}
@@ -1777,7 +1794,8 @@ base class MyBaseClass {
protected var data: i32;
}
class MyDerivedClass extends MyBaseClass {
class MyDerivedClass {
extend base: MyBaseClass;
fn UsesProtected[addr self: Self*]() {
// Can access protected members in derived class
var x: i32 = HelperClassFunction(3);
@@ -1975,9 +1993,10 @@ There are some opportunities to improve on and simplify the C++ story:
This design directly supports Carbon classes inheriting from a single C++ class.
```
class CarbonClass extends C++.CPlusPlusClass {
class CarbonClass {
extend base: Cpp.CPlusPlusClass;
fn Create() -> Self {
return {.base = C++.CPlusPlusClass(...), .other_fields = ...};
return {.base = Cpp.CPlusPlusClass(...), .other_fields = ...};
}
...
}
@@ -2132,7 +2151,7 @@ interface ConstructWidgetFrom {
fn Construct(Self) -> Widget;
}
external impl {.kind: WidgetKind, .size: i32}
impl {.kind: WidgetKind, .size: i32}
as ConstructWidgetFrom { ... }
```
@@ -2233,6 +2252,10 @@ the type of `U.x`."
- [No unqualified lookup when defining outside a scope](/proposals/p2287.md#no-unqualified-lookup-when-defining-outside-a-scope)
- [#2760: Consistent `class` and `interface` syntax](https://github.com/carbon-language/carbon-lang/pull/2760)
- [Use `extends` instead of `extend`](/proposals/p2760.md#use-extends-instead-of-extend)
- [List base class in class declaration](/proposals/p2760.md#list-base-class-in-class-declaration)
## References
- [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)
@@ -2244,3 +2267,4 @@ the type of `U.x`."
- [#1154: Destructors](https://github.com/carbon-language/carbon-lang/pull/1154)
- [#2107: Clarify rules around `Self` and `.Self`](https://github.com/carbon-language/carbon-lang/pull/2107)
- [#2287: Allow unqualified name lookup for class members](https://github.com/carbon-language/carbon-lang/pull/2287)
- [#2760: Consistent `class` and `interface` syntax](https://github.com/carbon-language/carbon-lang/pull/2760)
+1 -1
View File
@@ -235,7 +235,7 @@ with parentheses around the member name:
```
interface I { fn F[self: Self](); }
class X {}
external impl X as I { fn F[self: Self]() {} }
impl X as I { fn F[self: Self]() {} }
// `x.I.F()` would mean `(x.I).F()`.
fn Q(x: X) { x.(I.F)(); }
+5 -5
View File
@@ -205,7 +205,7 @@ interface AddWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint Add {
extends AddWith(Self) where .Result = Self;
extend AddWith(Self) where .Result = Self;
}
```
@@ -216,7 +216,7 @@ interface SubWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint Sub {
extends SubWith(Self) where .Result = Self;
extend SubWith(Self) where .Result = Self;
}
```
@@ -227,7 +227,7 @@ interface MulWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint Mul {
extends MulWith(Self) where .Result = Self;
extend MulWith(Self) where .Result = Self;
}
```
@@ -238,7 +238,7 @@ interface DivWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint Div {
extends DivWith(Self) where .Result = Self;
extend DivWith(Self) where .Result = Self;
}
```
@@ -249,7 +249,7 @@ interface ModWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint Mod {
extends ModWith(Self) where .Result = Self;
extend ModWith(Self) where .Result = Self;
}
```
+5 -5
View File
@@ -209,7 +209,7 @@ interface BitAndWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint BitAnd {
extends BitAndWith(Self) where .Result = Self;
extend BitAndWith(Self) where .Result = Self;
}
```
@@ -220,7 +220,7 @@ interface BitOrWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint BitOr {
extends BitOrWith(Self) where .Result = Self;
extend BitOrWith(Self) where .Result = Self;
}
```
@@ -231,7 +231,7 @@ interface BitXorWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint BitXor {
extends BitXorWith(Self) where .Result = Self;
extend BitXorWith(Self) where .Result = Self;
}
```
@@ -242,7 +242,7 @@ interface LeftShiftWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint LeftShift {
extends LeftShiftWith(Self) where .Result = Self;
extend LeftShiftWith(Self) where .Result = Self;
}
```
@@ -253,7 +253,7 @@ interface RightShiftWith(U:! type) {
fn Op[self: Self](other: U) -> Result;
}
constraint RightShift {
extends RightShiftWith(Self) where .Result = Self;
extend RightShiftWith(Self) where .Result = Self;
}
```
+12 -12
View File
@@ -260,7 +260,7 @@ interface EqWith(U:! type) {
}
}
constraint Eq {
extends EqWith(Self);
extend EqWith(Self);
}
```
@@ -275,7 +275,7 @@ class Path {
private var path: String;
private fn CanonicalPath[self: Self]() -> String;
external impl as Eq {
impl as Eq {
fn Equal[self: Self](other: Self) -> bool {
return (self.drive, self.CanonicalPath()) ==
(other.drive, other.CanonicalPath());
@@ -295,8 +295,8 @@ class MyInt {
var value: i32;
fn Value[self: Self]() -> i32 { return self.value; }
}
external impl i32 as ImplicitAs(MyInt);
external impl like MyInt as EqWith(like MyInt) {
impl i32 as ImplicitAs(MyInt);
impl like MyInt as EqWith(like MyInt) {
fn Equal[self: Self](other: Self) -> bool {
return self.Value() == other.Value();
}
@@ -315,7 +315,7 @@ and `NotEqual` to return `true` for the same pair of values. Additionally, these
operations should have no observable side-effects.
```
external impl like MyFloat as EqWith(like MyFloat) {
impl like MyFloat as EqWith(like MyFloat) {
fn Equal[self: MyFloat](other: MyFloat) -> bool {
if (self.IsNaN() or other.IsNaN()) {
return false;
@@ -334,8 +334,8 @@ external impl like MyFloat as EqWith(like MyFloat) {
Heterogeneous comparisons must be defined both ways around:
```
external impl like MyInt as EqWith(like MyFloat);
external impl like MyFloat as EqWith(like MyInt);
impl like MyInt as EqWith(like MyFloat);
impl like MyFloat as EqWith(like MyInt);
```
**TODO:** Add an adapter to the standard library to make it easy to define the
@@ -371,12 +371,12 @@ interface OrderedWith(U:! type) {
}
}
constraint Ordered {
extends OrderedWith(Self);
extend OrderedWith(Self);
}
// Ordering.Less < Ordering.Equivalent < Ordering.Greater.
// Ordering.Incomparable is incomparable with all three.
external impl Ordering as Ordered;
impl Ordering as Ordered;
```
**TODO:** Revise the above when we have a concrete design for enumerated types.
@@ -398,7 +398,7 @@ class MyWidget {
fn Size[self: Self]() -> i32 { return self.width * self.height; }
// Widgets are normally ordered by size.
external impl as Ordered {
impl as Ordered {
fn Compare[self: Self](other: Self) -> Ordering {
return self.Size().(Ordered.Compare)(other.Size());
}
@@ -418,8 +418,8 @@ heterogeneous comparisons must be defined both ways around:
fn ReverseOrdering(o: Ordering) -> Ordering {
return Ordering.Equivalent.(Ordered.Compare)(o);
}
external impl like MyInt as OrderedWith(like MyFloat);
external impl like MyFloat as OrderedWith(like MyInt) {
impl like MyInt as OrderedWith(like MyFloat);
impl like MyFloat as OrderedWith(like MyInt) {
fn Compare[self: Self](other: Self) -> Ordering {
return Reverse(other.(OrderedWith(Self).Compare)(self));
}
@@ -172,8 +172,8 @@ to `Base**` because that would allow storing a `Derived2*` into a `Derived*`:
```
abstract class Base {}
class Derived extends Base {}
class Derived2 extends Base {}
class Derived { extend base: Base; }
class Derived2 { extend base: Base; }
var d2: Derived2 = {};
var p: Derived*;
var q: Derived2* = &d2;
@@ -208,7 +208,7 @@ extends
```
interface ImplicitAs(Dest:! type) {
extends As(Dest);
extend As(Dest);
// Inherited from As(Dest):
// fn Convert[self: Self]() -> Dest;
}
+4 -4
View File
@@ -55,7 +55,7 @@ interface IndexWith(SubscriptType:! type) {
}
interface IndirectIndexWith(SubscriptType:! type) {
impl as IndexWith(SubscriptType);
require Self impls IndexWith(SubscriptType);
fn Addr[self: Self](subscript: SubscriptType) -> ElementType*;
}
```
@@ -74,7 +74,7 @@ implement `IndirectIndexWith(I)`:
`IndirectIndexWith` provides a blanket `final impl` for `IndexWith`:
```
final external impl forall
final impl forall
[SubscriptType:! type, T:! IndirectIndexWith(SubscriptType)]
T as IndexWith(SubscriptType) {
let ElementType:! type = T.(IndirectIndexWith(SubscriptType)).ElementType;
@@ -96,7 +96,7 @@ An array type could implement subscripting like so:
```
class Array(template T:! type) {
external impl as IndexWith(like i64) {
impl as IndexWith(like i64) {
let ElementType:! type = T;
fn At[self: Self](subscript: i64) -> T;
fn Addr[addr self: Self*](subscript: i64) -> T*;
@@ -108,7 +108,7 @@ And a type such as `std::span` could look like this:
```
class Span(T:! type) {
external impl as IndirectIndexWith(like i64) {
impl as IndirectIndexWith(like i64) {
let ElementType:! type = T;
fn Addr[self: Self](subscript: i64) -> T*;
}
+15 -14
View File
@@ -60,7 +60,7 @@ interface Widget {
class Cog {
var size: i32;
fn Make(size: i32) -> Self;
impl as Widgets.Widget;
extend impl as Widgets.Widget;
}
fn GrowSomeCogs() {
@@ -165,12 +165,12 @@ For example:
interface Printable {
fn Print[self: Self]();
}
external impl i32 as Printable;
impl i32 as Printable;
class Point {
var x: i32;
var y: i32;
// Internal impl injects the name `Print` into class `Point`.
impl as Printable;
extend impl as Printable;
}
fn PrintPointTwice() {
@@ -242,7 +242,7 @@ class Cowboy { fn Draw[self: Self](); }
interface Renderable {
fn Draw[self: Self]();
}
external impl Cowboy as Renderable { fn Draw[self: Self](); }
impl Cowboy as Renderable { fn Draw[self: Self](); }
fn DrawDirect(c: Cowboy) { c.Draw(); }
fn DrawGeneric[T:! Renderable](c: T) { c.Draw(); }
fn DrawTemplate[template T:! Renderable](c: T) { c.Draw(); }
@@ -257,7 +257,7 @@ fn Draw(c: Cowboy) {
}
class RoundWidget {
external impl as Renderable {
impl as Renderable {
fn Draw[self: Self]();
}
alias Draw = Renderable.Draw;
@@ -265,7 +265,7 @@ class RoundWidget {
class SquareWidget {
fn Draw[self: Self]() {}
external impl as Renderable {
impl as Renderable {
alias Draw = Self.Draw;
}
}
@@ -311,7 +311,7 @@ interface Addable {
}
class Integer {
impl as Addable {
extend impl as Addable {
// #3
fn Add[self: Self](other: Self) -> Self;
// #4, generated from default implementation for #2.
@@ -372,7 +372,7 @@ interface I {
let N:! i32;
}
class C {
impl as I where .N = 5 {
extend impl as I where .N = 5 {
// #2
fn F[self: C]() {}
}
@@ -417,7 +417,7 @@ interface Renderable {
}
class RoundWidget {
external impl as Renderable {
impl as Renderable {
// #2
fn Draw[self: Self]();
}
@@ -428,7 +428,7 @@ class RoundWidget {
class SquareWidget {
// #3
fn Draw[self: Self]() {}
external impl as Renderable {
impl as Renderable {
alias Draw = Self.Draw;
}
}
@@ -480,8 +480,9 @@ base class WidgetBase {
}
}
class TriangleWidget extends WidgetBase {
external impl as Renderable;
class TriangleWidget {
extend base: WidgetBase;
impl as Renderable;
}
fn DrawTriangle(t: TriangleWidget) {
// ✅ OK: name `Draw` resolves to `Draw` member of `WidgetBase`, which
@@ -582,7 +583,7 @@ always used for lookup.
interface Printable {
fn Print[self: Self]();
}
external impl i32 as Printable {
impl i32 as Printable {
fn Print[self: Self]();
}
fn MemberAccess(n: i32) {
@@ -621,7 +622,7 @@ class A {
interface B {
fn F();
}
external impl A as B;
impl A as B;
fn Use(a: A) {
// Calls member `F` of class `A.B`.
File diff suppressed because it is too large Load Diff
+24 -22
View File
@@ -205,27 +205,27 @@ class Song {
// ...
// Implementing `Printable` for `Song` inside the definition of `Song`
// without the keyword `external` means all names of `Printable`, such
// with the keyword `extend` means all names of `Printable`, such
// as `F`, are included as a part of the `Song` API.
impl as Printable {
extend impl as Printable {
// Could use `Self` in place of `Song` here.
fn Print[self: Song]() { ... }
}
}
// Implement `Comparable` for `Song` without changing the API of `Song`
// using an `external impl` declaration. This may be defined in either
// the library defining `Song` or `Comparable`.
external impl Song as Comparable {
// using an `impl` declaration without `extend`. This may be defined in
// either the library defining `Song` or `Comparable`.
impl Song as Comparable {
// Could use either `Self` or `Song` here.
fn Less[self: Self](rhs: Self) -> bool { ... }
}
```
Implementations may be defined within the class definition itself or
out-of-line. Implementations may optionally start with the `external` keyword to
say the members of the interface are not members of the class. Out-of-line
implementations must be external. External implementations may be defined in the
out-of-line. Implementations may optionally start with the `extend` keyword to
say the members of the interface are also members of the class, which may only
be used in a class scope. Otherwise, implementations may be defined in the
library defining either the class or the interface.
#### Accessing members of interfaces
@@ -355,12 +355,12 @@ interface Equatable {
// `Iterable` requires that `Equatable` is implemented.
interface Iterable {
impl as Equatable;
require Self impls Equatable;
fn Advance[addr self: Self*]();
}
```
The `extends` keyword is used to [extend](terminology.md#extending-an-interface)
The `extend` keyword is used to [extend](terminology.md#extending-an-interface)
another interface. If interface `Derived` extends interface `Base`, `Base`'s
interface is both required and all its methods are included in `Derived`'s
interface.
@@ -368,12 +368,12 @@ interface.
```
// `Hashable` extends `Equatable`.
interface Hashable {
extends Equatable;
extend Equatable;
fn Hash[self: Self]() -> u64;
}
// `Hashable` is equivalent to:
interface Hashable {
impl as Equatable;
require Self impls Equatable;
alias IsEqual = Equatable.IsEqual;
fn Hash[self: Self]() -> u64;
}
@@ -385,7 +385,7 @@ methods in the implementation of the derived interface.
```
class Key {
// ...
impl as Hashable {
extend impl as Hashable {
fn IsEqual[self: Key](rhs: Key) -> bool { ... }
fn Hash[self: Key]() -> u64 { ... }
}
@@ -439,8 +439,8 @@ applications and capabilities not covered here.
```
constraint Combined {
impl as Renderable;
impl as EndOfGame;
require Self impls Renderable;
require Self impls EndOfGame;
alias Draw_Renderable = Renderable.Draw;
alias Draw_EndOfGame = EndOfGame.Draw;
alias SetWinner = EndOfGame.SetWinner;
@@ -472,7 +472,7 @@ For example: If there were a class `CDCover` defined this way:
```
class CDCover {
impl as Printable {
extend impl as Printable {
...
}
}
@@ -503,12 +503,14 @@ In this example, we have multiple ways of sorting a collection of `Song` values.
```
class Song { ... }
adapter SongByArtist extends Song {
impl as Comparable { ... }
class SongByArtist {
extend adapt Song;
extend impl as Comparable { ... }
}
adapter SongByTitle extends Song {
impl as Comparable { ... }
class SongByTitle {
extend adapt Song;
extend impl as Comparable { ... }
}
```
@@ -610,7 +612,7 @@ of associated types (and other associated constants).
```
class Vector(T:! Movable) {
impl as Stack where .ElementType = T { ... }
extend impl as Stack where .ElementType = T { ... }
}
```
@@ -649,7 +651,7 @@ supports any type implicitly convertible to a specified type, using `like`:
// Support multiplying values of type `Distance` with
// values of type `f64` or any type implicitly
// convertible to `f64`.
external impl Distance as MultipliableWith(like f64) ...
impl Distance as MultipliableWith(like f64) ...
```
## Future work
+4 -4
View File
@@ -347,9 +347,9 @@ instead of associated entity.
## Impl: Implementation of an interface
An _impl_ is an implementation of an interface for a specific type. It is the
place where the function bodies are defined, values for associated types, etc.
are given. Implementations are needed for
An _impl_ is an implementation of an interface for a specific type, called the
_implementing type_. It is the place where the function bodies are defined,
values for associated types, etc. are given. Implementations are needed for
[nominal interfaces](#nominal-interfaces);
[structural interfaces](#structural-interfaces) and
[named constraints](#named-constraints) define conformance implicitly instead of
@@ -678,7 +678,7 @@ class Fruit;
class FruitStack {
// Implement `Stack` for `FruitStack`
// with `ElementType` set to `Fruit`.
impl as Stack where .ElementType == Fruit { ... }
extend impl as Stack where .ElementType == Fruit { ... }
}
```
+6 -6
View File
@@ -83,9 +83,9 @@ match (my_opt) {
have limited flexibility. There is no way to control the representation of a
`choice` type, or define methods or other members for it (although you can
extend it to implement interfaces, using an
[`external impl`](generics/overview.md#implementing-interfaces) or
[`adapter`](generics/overview.md#adapting-types)). However, a `class` type can
be extended to behave like a sum type. This is much more verbose than a `choice`
[external `impl`](generics/overview.md#implementing-interfaces) or
[adapter](generics/overview.md#adapting-types)). However, a `class` type can be
extended to behave like a sum type. This is much more verbose than a `choice`
declaration, but gives the author full control over the representation and class
members.
@@ -143,9 +143,9 @@ class Optional(T:! type) {
private var has_value: bool;
private var value: T;
external impl as Match {
impl as Match {
interface Continuation {
extends Match.BaseContinuation;
extend Match.BaseContinuation;
fn Some[addr self: Self*](value: T) -> ReturnType;
fn None[addr self: Self*]() -> ReturnType;
}
@@ -170,7 +170,7 @@ look, if it were written in Carbon:
```carbon
class __MatchStatementImpl {
impl as Match(Optional.MatchContinuation) where .ReturnType = () {
extend impl as Match(Optional.MatchContinuation) where .ReturnType = () {
fn Some(the_value: i32) {
Print(the_value);
}