mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 06:34:41 +01:00
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:
+26
-17
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)(); }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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*;
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
|
||||
+417
-383
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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 { ... }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user