diff --git a/docs/design/README.md b/docs/design/README.md index aef2dc785e6b2..78b3f7d74f27e 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -1767,16 +1767,16 @@ class Point { return Math.Sqrt(dx * dx + dy * dy); } // Mutating method declaration - fn Offset[addr self: Self*](dx: i32, dy: i32); + fn Offset[ref self: Self](dx: i32, dy: i32); var x: i32; var y: i32; } // Out-of-line definition of method declared inline -fn Point.Offset[addr self: Self*](dx: i32, dy: i32) { - self->x += dx; - self->y += dy; +fn Point.Offset[ref self: Self](dx: i32, dy: i32) { + self.x += dx; + self.y += dy; } var origin: Point = {.x = 0, .y = 0}; @@ -1796,10 +1796,9 @@ two methods `Distance` and `Offset`: - `Distance` computes and returns the distance to another point, without modifying the `Point`. This is signified using `[self: Self]` in the method declaration. -- `origin.Offset(`...`)` does modify the value of `origin`. This is signified - using `[addr self: Self*]` in the method declaration. Since calling this - method requires taking the [non-`const`](#const) address of `origin`, it may - only be called on [reference expressions](#expression-categories). +- `origin.Offset(`...`)` _does_ modify the value of `origin`. This is + signified using `[ref self: Self]` in the method declaration. It may only be + called on [reference expressions](#expression-categories). - Methods may be declared lexically inline like `Distance`, or lexically out of line like `Offset`. @@ -1955,7 +1954,7 @@ names resolvable by the compiler, and don't act like forward declarations. A destructor for a class is custom code executed when the lifetime of a value of that type ends. They are defined with `fn destroy` followed by either -`[self: Self]` or `[addr self: Self*]` (as is done with [methods](#methods)) and +`[self: Self]` or `[ref self: Self]` (as is done with [methods](#methods)) and the block of code in the class definition, as in: ```carbon @@ -1969,7 +1968,7 @@ or: ```carbon class MyClass { // Can modify `self` in the body. - fn destroy[addr self: Self*]() { ... } + fn destroy[ref self: Self]() { ... } } ``` @@ -2004,8 +2003,8 @@ For every type `MyClass`, there is the type `const MyClass` such that: has type `const T`. - While all of the member names in `MyClass` are also member names in `const MyClass`, the effective API of a `const MyClass` reference expression - is a subset of `MyClass`, because only `addr` methods accepting a - `const Self*` will be valid. + is a subset of `MyClass`, because only `ref` methods accepting a + `const Self` will be valid. Note that `const` binds more tightly than postfix-`*` for forming a pointer type, so `const MyClass*` is equal to `(const MyClass)*`. @@ -2996,8 +2995,8 @@ associated constant to represent the type of elements stored in the stack. ``` interface StackInterface { let ElementType:! Movable; - fn Push[addr self: Self*](value: ElementType); - fn Pop[addr self: Self*]() -> ElementType; + fn Push[ref self: Self](value: ElementType); + fn Pop[ref self: Self]() -> ElementType; fn IsEmpty[self: Self]() -> bool; } ``` @@ -3008,14 +3007,14 @@ for the `ElementType` member of the interface using a `where` clause: ```carbon class IntStack { extend impl as StackInterface where .ElementType = i32 { - fn Push[addr self: Self*](value: i32); + fn Push[ref self: Self](value: i32); // ... } } class FruitStack { extend impl as StackInterface where .ElementType = Fruit { - fn Push[addr self: Self*](value: Fruit); + fn Push[ref self: Self](value: Fruit); // ... } } @@ -3043,8 +3042,8 @@ values of any type `T`: ```carbon class Stack(T:! type) { - fn Push[addr self: Self*](value: T); - fn Pop[addr self: Self*]() -> T; + fn Push[ref self: Self](value: T); + fn Pop[ref self: Self]() -> T; var storage: Array(T); } diff --git a/docs/design/assignment.md b/docs/design/assignment.md index 6171a47479c9e..a8f7ee6a0f480 100644 --- a/docs/design/assignment.md +++ b/docs/design/assignment.md @@ -73,9 +73,8 @@ standard library. ## Syntax The operands of these operators can be any [expression](expressions/README.md). -However, the first operand must be modifiable because it is passed to an -`[addr self: Self*]` parameter, which disallows most expression forms other -than: +However, the first operand must be modifiable because it is passed to a +`[ref self: Self]` parameter, which disallows most expression forms other than: - The name of a `var` binding. - A dereference of a pointer. @@ -175,7 +174,7 @@ provided for built-in types as necessary to give the semantics described above. ``` // Simple `=`. interface AssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint Assign { extend AssignWith(Self); } ``` @@ -189,7 +188,7 @@ Given `var x: T` and `y: U`: ``` // Compound `+=`. interface AddAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint AddAssign { extend AddAssignWith(Self); } ``` @@ -197,7 +196,7 @@ constraint AddAssign { extend AddAssignWith(Self); } ``` // Compound `-=`. interface SubAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint SubAssign { extend SubAssignWith(Self); } ``` @@ -205,7 +204,7 @@ constraint SubAssign { extend SubAssignWith(Self); } ``` // Compound `*=`. interface MulAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint MulAssign { extend MulAssignWith(Self); } ``` @@ -213,7 +212,7 @@ constraint MulAssign { extend MulAssignWith(Self); } ``` // Compound `/=`. interface DivAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint DivAssign { extend DivAssignWith(Self); } ``` @@ -221,16 +220,16 @@ constraint DivAssign { extend DivAssignWith(Self); } ``` // Compound `%=`. interface ModAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint ModAssign { extend ModAssignWith(Self); } ``` ``` // Increment `++`. -interface Inc { fn Op[addr self: Self*](); } +interface Inc { fn Op[ref self: Self](); } // Decrement `++`. -interface Dec { fn Op[addr self: Self*](); } +interface Dec { fn Op[ref self: Self](); } ``` Given `var x: T` and `y: U`: @@ -248,7 +247,7 @@ Given `var x: T` and `y: U`: ``` // Compound `&=`. interface BitAndAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint BitAndAssign { extend BitAndAssignWith(Self); } ``` @@ -256,7 +255,7 @@ constraint BitAndAssign { extend BitAndAssignWith(Self); } ``` // Compound `|=`. interface BitOrAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint BitOrAssign { extend BitOrAssignWith(Self); } ``` @@ -264,7 +263,7 @@ constraint BitOrAssign { extend BitOrAssignWith(Self); } ``` // Compound `^=`. interface BitXorAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint BitXorAssign { extend BitXorAssignWith(Self); } ``` @@ -272,7 +271,7 @@ constraint BitXorAssign { extend BitXorAssignWith(Self); } ``` // Compound `<<=`. interface LeftShiftAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); } ``` @@ -280,7 +279,7 @@ constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); } ``` // Compound `>>=`. interface RightShiftAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); + fn Op[ref self: Self](other: U); } constraint RightShiftAssign { extend RightShiftAssignWith(Self); } ``` @@ -310,7 +309,7 @@ This defaulting is accomplished by a parameterized implementation of ``` impl forall [U:! type, T:! OpWith(U) where .Self impls AssignWith(.Self.Result)] T as OpAssignWith(U) { - fn Op[addr self: Self*](other: U) { + fn Op[ref self: Self](other: U) { // Here, `$` is the operator described by `OpWith`. *self = *self $ other; } diff --git a/docs/design/classes.md b/docs/design/classes.md index 01ee5fa8371e0..1efdf4a278fbf 100644 --- a/docs/design/classes.md +++ b/docs/design/classes.md @@ -903,14 +903,14 @@ class Circle { fn Diameter[self: Self]() -> f32 { return self.radius * 2; } - fn Expand[addr self: Self*](distance: f32); + fn Expand[ref self: Self](distance: f32); var center: Point; var radius: f32; } -fn Circle.Expand[addr self: Self*](distance: f32) { - self->radius += distance; +fn Circle.Expand[ref self: Self](distance: f32) { + self.radius += distance; } var c: Circle = {.center = Point.Origin(), .radius = 1.5 }; @@ -925,12 +925,11 @@ Assert(Math.Abs(c.Diameter() - 4.0) < 0.001); the `Circle` instance. This is signified using `[self: Self]` in the method declaration. - `c.Expand(`...`)` does modify the value of `c`. This is signified using - `[addr self: Self*]` in the method declaration. + `[ref self: Self]` in the method declaration. -The pattern '`addr self:` _type_' means "first take the address of the argument, -which must be an -[l-value](), and -then match pattern '`self:` _type_' against it". +The pattern '`ref self:` _type_' means "the argument must be a +[reference expression](/docs/design/values.md#reference-expressions), and must +match the pattern '`self:` _type_'". If the method declaration also includes [deduced compile-time parameters](/docs/design/generics/overview.md#deduced-parameters), @@ -1585,7 +1584,7 @@ or: ```carbon class MyClass { // Can modify `self` in the body. - fn destroy[addr self: Self*]() { ... } + fn destroy[ref self: Self]() { ... } } ``` @@ -1608,9 +1607,9 @@ Destructors may be declared in class scope and then defined out-of-line: ```carbon class MyClass { - fn destroy[addr self: Self*](); + fn destroy[ref self: Self](); } -fn MyClass.destroy[addr self: Self*]() { ... } +fn MyClass.destroy[ref self: Self]() { ... } ``` It is illegal to delete an instance of a derived class through a pointer to one @@ -1622,12 +1621,12 @@ must be `override`: ```carbon base class MyBaseClass { - virtual fn destroy[addr self: Self*]() { ... } + virtual fn destroy[ref self: Self]() { ... } } class MyDerivedClass { extend base: MyBaseClass; - override fn destroy[addr self: Self*]() { ... } + override fn destroy[ref self: Self]() { ... } } ``` @@ -1677,8 +1676,8 @@ call the `UnsafeDelete` method instead. Note that you may not call ``` interface Allocator { // ... - fn Delete[T:! Deletable, addr self: Self*](p: T*); - fn UnsafeDelete[T:! Destructible, addr self: Self*](p: T*); + fn Delete[T:! Deletable, ref self: Self](p: T*); + fn UnsafeDelete[T:! Destructible, ref self: Self](p: T*); } ``` @@ -1835,10 +1834,10 @@ base class MyBaseClass { class MyDerivedClass { extend base: MyBaseClass; - fn UsesProtected[addr self: Self*]() { + fn UsesProtected[ref self: Self]() { // Can access protected members in derived class var x: i32 = HelperClassFunction(3); - self->data = self->HelperMethod(x); + self.data = self.HelperMethod(x); } } ``` diff --git a/docs/design/expressions/member_access.md b/docs/design/expressions/member_access.md index ecf28af15918b..8d8a51ffff0ad 100644 --- a/docs/design/expressions/member_access.md +++ b/docs/design/expressions/member_access.md @@ -76,7 +76,7 @@ For example: namespace Widgets; interface Widgets.Widget { - fn Grow[addr self: Self*](factor: f64); + fn Grow[ref self: Self](factor: f64); } class Widgets.Cog { @@ -765,19 +765,15 @@ If instance binding is performed: - For a method, the result is a _bound method_, which is a value `F` such that a function call `F(args)` behaves the same as a call to `M(args)` with the - `self` parameter initialized by a corresponding recipient argument: - - - If the method declares its `self` parameter with `addr`, the recipient - argument is `&x`. - - Otherwise, the recipient argument is `x`. + `self` parameter initialized by `x`. ```carbon class Blob { - fn Mutate[addr self: Self*](n: i32); + fn Mutate[ref self: Self](n: i32); } fn F(p: Blob*) { // ✅ OK, forms bound method `((*p).M)` and calls it. - // This calls `Blob.Mutate` with `self` initialized by `&(*p)` + // This calls `Blob.Mutate` with `self` initialized by `*p` // and `n` initialized by `5`. (*p).Mutate(5); diff --git a/docs/design/generics/appendix-witness.md b/docs/design/generics/appendix-witness.md index dbaa28ab4fece..d5767a23ac958 100644 --- a/docs/design/generics/appendix-witness.md +++ b/docs/design/generics/appendix-witness.md @@ -241,12 +241,12 @@ witness table. ``` interface Iterator { - fn Advance[addr self: Self*](); + fn Advance[ref self: Self](); } interface Container { let IteratorType:! Iterator; - fn Begin[addr self: Self*]() -> IteratorType; + fn Begin[ref self: Self]() -> IteratorType; } ``` diff --git a/docs/design/generics/details.md b/docs/design/generics/details.md index 59eeff36084af..11a4988efdc11 100644 --- a/docs/design/generics/details.md +++ b/docs/design/generics/details.md @@ -1210,7 +1210,7 @@ we use the same semantics and `require Self impls` syntax as we do for interface Equatable { fn Equals[self: Self](rhs: Self) -> bool; } interface Iterable { - fn Advance[addr self: Self*]() -> bool; + fn Advance[ref self: Self]() -> bool; require Self impls Equatable; } @@ -1431,7 +1431,7 @@ Conversely, an `interface` can extend a `constraint`: interface MovieCodec { extend Combined; - fn Load[addr self: Self*](filename: String); + fn Load[ref self: Self](filename: String); } ``` @@ -1445,7 +1445,7 @@ interface MovieCodec { require Self impls Job; alias Run = Job.Run; - fn Load[addr self: Self*](filename: String); + fn Load[ref self: Self](filename: String); } ``` @@ -1459,19 +1459,19 @@ Consider this set of interfaces, simplified from ```carbon interface Graph { - fn Source[addr self: Self*](e: EdgeDescriptor) -> VertexDescriptor; - fn Target[addr self: Self*](e: EdgeDescriptor) -> VertexDescriptor; + fn Source[ref self: Self](e: EdgeDescriptor) -> VertexDescriptor; + fn Target[ref self: Self](e: EdgeDescriptor) -> VertexDescriptor; } interface IncidenceGraph { extend Graph; - fn OutEdges[addr self: Self*](u: VertexDescriptor) + fn OutEdges[ref self: Self](u: VertexDescriptor) -> (EdgeIterator, EdgeIterator); } interface EdgeListGraph { extend Graph; - fn Edges[addr self: Self*]() -> (EdgeIterator, EdgeIterator); + fn Edges[ref self: Self]() -> (EdgeIterator, EdgeIterator); } ``` @@ -1498,11 +1498,11 @@ though could be defined in the `impl` block of `IncidenceGraph`, extend impl as IncidenceGraph { fn Source[self: Self](e: EdgeDescriptor) -> VertexDescriptor { ... } fn Target[self: Self](e: EdgeDescriptor) -> VertexDescriptor { ... } - fn OutEdges[addr self: Self*](u: VertexDescriptor) + fn OutEdges[ref self: Self](u: VertexDescriptor) -> (EdgeIterator, EdgeIterator) { ... } } extend impl as EdgeListGraph { - fn Edges[addr self: Self*]() -> (EdgeIterator, EdgeIterator) { ... } + fn Edges[ref self: Self]() -> (EdgeIterator, EdgeIterator) { ... } } } ``` @@ -1514,12 +1514,12 @@ though could be defined in the `impl` block of `IncidenceGraph`, class MyEdgeListIncidenceGraph { extend impl as IncidenceGraph { fn Source[self: Self](e: EdgeDescriptor) -> VertexDescriptor { ... } - fn OutEdges[addr self: Self*](u: VertexDescriptor) + fn OutEdges[ref self: Self](u: VertexDescriptor) -> (EdgeIterator, EdgeIterator) { ... } } extend impl as EdgeListGraph { fn Target[self: Self](e: EdgeDescriptor) -> VertexDescriptor { ... } - fn Edges[addr self: Self*]() -> (EdgeIterator, EdgeIterator) { ... } + fn Edges[ref self: Self]() -> (EdgeIterator, EdgeIterator) { ... } } } ``` @@ -2021,10 +2021,10 @@ as an associated constant. interface NSpacePoint { let N:! i32; // The following require: 0 <= i < N. - fn Get[addr self: Self*](i: i32) -> f64; - fn Set[addr self: Self*](i: i32, value: f64); + fn Get[ref self: Self](i: i32) -> f64; + fn Set[ref self: Self](i: i32, value: f64); // Associated constants may be used in signatures: - fn SetAll[addr self: Self*](value: Array(f64, N)); + fn SetAll[ref self: Self](value: Array(f64, N)); } ``` @@ -2044,17 +2044,17 @@ a [`where` clause](#where-constraints). For example, implementations of ```carbon class Point2D { extend impl as NSpacePoint where .N = 2 { - fn Get[addr self: Self*](i: i32) -> f64 { ... } - fn Set[addr self: Self*](i: i32, value: f64) { ... } - fn SetAll[addr self: Self*](value: Array(f64, 2)) { ... } + fn Get[ref self: Self](i: i32) -> f64 { ... } + fn Set[ref self: Self](i: i32, value: f64) { ... } + fn SetAll[ref self: Self](value: Array(f64, 2)) { ... } } } class Point3D { extend impl as NSpacePoint where .N = 3 { - fn Get[addr self: Self*](i: i32) -> f64 { ... } - fn Set[addr self: Self*](i: i32, value: f64) { ... } - fn SetAll[addr self: Self*](value: Array(f64, 3)) { ... } + fn Get[ref self: Self](i: i32) -> f64 { ... } + fn Set[ref self: Self](i: i32, value: f64) { ... } + fn SetAll[ref self: Self](value: Array(f64, 3)) { ... } } } ``` @@ -2154,9 +2154,9 @@ a specified name. For example: ```carbon interface StackAssociatedFacet { let ElementType:! type; - fn Push[addr self: Self*](value: ElementType); - fn Pop[addr self: Self*]() -> ElementType; - fn IsEmpty[addr self: Self*]() -> bool; + fn Push[ref self: Self](value: ElementType); + fn Pop[ref self: Self]() -> ElementType; + fn IsEmpty[ref self: Self]() -> bool; } ``` @@ -2169,26 +2169,26 @@ of `StackAssociatedFacet` must also define. For example, maybe a `DynamicArray` ```carbon class DynamicArray(T:! type) { class IteratorType { ... } - fn Begin[addr self: Self*]() -> IteratorType; - fn End[addr self: Self*]() -> IteratorType; - fn Insert[addr self: Self*](pos: IteratorType, value: T); - fn Remove[addr self: Self*](pos: IteratorType); + fn Begin[ref self: Self]() -> IteratorType; + fn End[ref self: Self]() -> IteratorType; + fn Insert[ref self: Self](pos: IteratorType, value: T); + fn Remove[ref self: Self](pos: IteratorType); // Set the associated facet `ElementType` to `T`. extend impl as StackAssociatedFacet where .ElementType = T { - fn Push[addr self: Self*](value: ElementType) { - self->Insert(self->End(), value); + fn Push[ref self: Self](value: ElementType) { + self.Insert(self.End(), value); } - fn Pop[addr self: Self*]() -> ElementType { - var pos: IteratorType = self->End(); - Assert(pos != self->Begin()); + fn Pop[ref self: Self]() -> ElementType { + var pos: IteratorType = self.End(); + Assert(pos != self.Begin()); --pos; returned var ret: ElementType = *pos; - self->Remove(pos); + self.Remove(pos); return var; } - fn IsEmpty[addr self: Self*]() -> bool { - return self->Begin() == self->End(); + fn IsEmpty[ref self: Self]() -> bool { + return self.Begin() == self.End(); } } } @@ -2290,9 +2290,9 @@ after the name of the interface: ```carbon interface StackParameterized(ElementType:! type) { - fn Push[addr self: Self*](value: ElementType); - fn Pop[addr self: Self*]() -> ElementType; - fn IsEmpty[addr self: Self*]() -> bool; + fn Push[ref self: Self](value: ElementType); + fn Pop[ref self: Self]() -> ElementType; + fn IsEmpty[ref self: Self]() -> bool; } ``` @@ -2304,25 +2304,25 @@ class Produce { var fruit: DynamicArray(Fruit); var veggie: DynamicArray(Veggie); extend impl as StackParameterized(Fruit) { - fn Push[addr self: Self*](value: Fruit) { - self->fruit.Push(value); + fn Push[ref self: Self](value: Fruit) { + self.fruit.Push(value); } - fn Pop[addr self: Self*]() -> Fruit { - return self->fruit.Pop(); + fn Pop[ref self: Self]() -> Fruit { + return self.fruit.Pop(); } - fn IsEmpty[addr self: Self*]() -> bool { - return self->fruit.IsEmpty(); + fn IsEmpty[ref self: Self]() -> bool { + return self.fruit.IsEmpty(); } } extend impl as StackParameterized(Veggie) { - fn Push[addr self: Self*](value: Veggie) { - self->veggie.Push(value); + fn Push[ref self: Self](value: Veggie) { + self.veggie.Push(value); } - fn Pop[addr self: Self*]() -> Veggie { - return self->veggie.Pop(); + fn Pop[ref self: Self]() -> Veggie { + return self.veggie.Pop(); } - fn IsEmpty[addr self: Self*]() -> bool { - return self->veggie.IsEmpty(); + fn IsEmpty[ref self: Self]() -> bool { + return self.veggie.IsEmpty(); } } } @@ -2430,7 +2430,7 @@ parameters are required to always be different. For example: ```carbon interface Map(FromType:! type, ToType:! type) { - fn Map[addr self: Self*](needle: FromType) -> Optional(ToType); + fn Map[ref self: Self](needle: FromType) -> Optional(ToType); } class Bijection(FromType:! type, ToType:! type) { extend impl as Map(FromType, ToType) { ... } @@ -2658,7 +2658,7 @@ interface Container { let SliceType:! Container where .Self impls SliceConstraint(ElementType, .Self); // `Self` means the type implementing `Container`. - fn GetSlice[addr self: Self*] + fn GetSlice[ref self: Self] (start: IteratorType, end: IteratorType) -> SliceType; } @@ -2768,7 +2768,7 @@ with any mentioned parameters substituted into that type. interface Container { let Element:! type; let Slice:! Container where .Element = Element; - fn Add[addr self: Self*](x: Element); + fn Add[ref self: Self](x: Element); } // `T.Slice.Element` rewritten to `T.Element` // because type of `T.Slice` says `.Element = Element`. @@ -2960,7 +2960,7 @@ interface Edge { interface Node { let E:! EdgeFor(Self); fn GetE[self: Self]() -> E; - fn AddE[addr self: Self*](e: E); + fn AddE[ref self: Self](e: E); fn NearN[self: Self](n: Self) -> bool; } @@ -6295,7 +6295,7 @@ class HashMap( // `Self` is `HashMap(KeyT, ValueT)`. // Class parameters may be used in function signatures. - fn Insert[addr self: Self*](k: KeyT, v: ValueT); + fn Insert[ref self: Self](k: KeyT, v: ValueT); // Class parameters may be used in field types. private var buckets: DynArray((KeyT, ValueT)); @@ -6371,7 +6371,7 @@ its elements implement the `Ordered` interface: ```carbon class DynArray(T:! type) { // `DynArray(T)` has a `Sort()` method if `T impls Ordered`. - fn Sort[C:! Ordered, addr self: DynArray(C)*](); + fn Sort[C:! Ordered, ref self: DynArray(C)](); } ``` diff --git a/docs/design/generics/overview.md b/docs/design/generics/overview.md index 3054b27fe8f5f..cf6b468e74a29 100644 --- a/docs/design/generics/overview.md +++ b/docs/design/generics/overview.md @@ -390,7 +390,7 @@ interface Equatable { // `Iterable` requires that `Equatable` is implemented. interface Iterable { require Self impls Equatable; - fn Advance[addr self: Self*](); + fn Advance[ref self: Self](); } ``` @@ -442,9 +442,9 @@ interface Renderable { fn Draw[self: Self](); } interface EndOfGame { - fn SetWinner[addr self: Self*](player: i32); + fn SetWinner[ref self: Self](player: i32); // Indicate the game was a draw - fn Draw[addr self: Self*](); + fn Draw[ref self: Self](); } fn F[T:! Renderable & EndOfGame](game_state: T*) -> (i32, i32) { @@ -568,9 +568,9 @@ convenient to use. Imagine a `Stack` interface. Different types implementing ``` interface Stack { let ElementType:! Movable; - fn Push[addr self: Self*](value: ElementType); - fn Pop[addr self: Self*]() -> ElementType; - fn IsEmpty[addr self: Self*]() -> bool; + fn Push[ref self: Self](value: ElementType); + fn Pop[ref self: Self]() -> ElementType; + fn IsEmpty[ref self: Self]() -> bool; } ``` diff --git a/docs/design/generics/terminology.md b/docs/design/generics/terminology.md index f36cf8490a7b2..2efeee461fdb1 100644 --- a/docs/design/generics/terminology.md +++ b/docs/design/generics/terminology.md @@ -752,8 +752,8 @@ associated constants. // Stack using associated facets interface Stack { let ElementType:! type; - fn Push[addr self: Self*](value: ElementType); - fn Pop[addr self: Self*]() -> ElementType; + fn Push[ref self: Self](value: ElementType); + fn Pop[ref self: Self]() -> ElementType; } // Works on any type implementing `Stack`. Return type diff --git a/docs/design/lambdas.md b/docs/design/lambdas.md index efaf51cbc4dcb..2211744078851 100644 --- a/docs/design/lambdas.md +++ b/docs/design/lambdas.md @@ -474,7 +474,7 @@ let lambda: auto = fn [self] { self.F(); }; Note: Following [#3720](https://github.com/carbon-language/carbon-lang/pull/3720), an expression -of the form `x.(F)`, where `F` is a function with a `self` or `addr self` +of the form `x.(F)`, where `F` is a function with a `self` or `ref self` parameter, produces a callable that holds the value of `x`, and does not hold the value of `F`. As a consequence, we can't support combining captures and function fields with a `self` parameter. diff --git a/docs/design/lexical_conventions/words.md b/docs/design/lexical_conventions/words.md index b10ddcaa5c27a..ea2d0eff8230d 100644 --- a/docs/design/lexical_conventions/words.md +++ b/docs/design/lexical_conventions/words.md @@ -47,7 +47,6 @@ The following words are interpreted as keywords: - `abstract` - `adapt` -- `addr` - `alias` - `and` - `as` @@ -89,6 +88,7 @@ The following words are interpreted as keywords: - `partial` - `private` - `protected` +- `ref` - `require` - `return` - `returned` diff --git a/docs/design/sum_types.md b/docs/design/sum_types.md index fcd984c0bc59e..b47dd6dc5443d 100644 --- a/docs/design/sum_types.md +++ b/docs/design/sum_types.md @@ -146,8 +146,8 @@ class Optional(T:! type) { impl as Match { interface Continuation { extend Match.BaseContinuation; - fn Some[addr self: Self*](value: T) -> ReturnType; - fn None[addr self: Self*]() -> ReturnType; + fn Some[ref self: Self](value: T) -> ReturnType; + fn None[ref self: Self]() -> ReturnType; } fn Op[self: Self, C:! Continuation](continuation: C*) -> C.ReturnType { diff --git a/docs/design/templates.md b/docs/design/templates.md index fe77637fbe4e7..659f3d8c7015f 100644 --- a/docs/design/templates.md +++ b/docs/design/templates.md @@ -47,8 +47,8 @@ bound early to the extent possible. For example: class Stack(template T:! type) { var storage: Array(T); - fn Push[addr self: Self*](value: T); - fn Pop[addr self: Self*]() -> T; + fn Push[ref self: Self](value: T); + fn Pop[ref self: Self]() -> T; } ``` diff --git a/docs/design/values.md b/docs/design/values.md index 4552f6b26e624..a36bc07dc2cbe 100644 --- a/docs/design/values.md +++ b/docs/design/values.md @@ -263,11 +263,6 @@ makes this a use case that requires a special marking on the declaration. _Reference expressions_ refer to _objects_ with _storage_ where a value may be read or written and the object's address can be taken. -Calling a [method](/docs/design/classes.md#methods) on a reference expression -where the method's `self` parameter has an `addr` specifier can always -implicitly take the address of the referred-to object. This address is passed as -a [pointer](#pointers) to the `self` parameter for such methods. - There are two sub-categories of reference expressions: _durable_ and _ephemeral_. These refine the _lifetime_ of the underlying storage and provide safety restrictions reflecting that lifetime. @@ -312,15 +307,15 @@ expressions_. They still refer to an object with storage, but it may be storage that will not outlive the full expression. Because the storage is only temporary, we impose restrictions on where these reference expressions can be used: their address can only be taken implicitly as part of a method call whose -`self` parameter is marked with the `addr` specifier. +`self` parameter is marked with the `ref` specifier. **Future work:** The current design allows directly requiring an ephemeral -reference for `addr`-methods because this replicates the flexibility in C++ -- +reference for `ref`-methods because this replicates the flexibility in C++ -- very few C++ methods are L-value-ref-qualified which would have a similar effect -to `addr`-methods requiring a durable reference expression. This is leveraged +to `ref`-methods requiring a durable reference expression. This is leveraged frequently in C++ for builder APIs and other patterns. However, Carbon provides more tools in this space than C++ already, and so it may be worth evaluating -whether we can switch `addr`-methods to the same restrictions as assignment and +whether we can switch `ref`-methods to the same restrictions as assignment and `&`. Temporaries would never have their address escaped (in a safe way) in that world and there would be fewer different kinds of entities. But this is reserved for future work as we should be very careful about the expressivity hit being @@ -473,7 +468,7 @@ to the operation in question. For example: ```carbon class S { fn ValueMemberFunction[self: Self](); - fn AddrMemberFunction[addr self: const Self*](); + fn RefMemberFunction[ref self: const Self](); } fn F(s_value: S) { @@ -481,7 +476,7 @@ fn F(s_value: S) { s_value.ValueMemberFunction(); // This requires an unsafe marker in the syntax. - s_value.unsafe AddrMemberFunction(); + s_value.unsafe RefMemberFunction(); } ``` @@ -794,7 +789,7 @@ _thread-safe_ interface subset of an otherwise _thread-compatible_ type. Note that `const T` is a type qualification and is generally orthogonal to expression categories or what form of pattern is used, including for object -parameters. Notionally, it can occur both with `addr` and value object +parameters. Notionally, it can occur both with `ref` and value object parameters. However, on value patterns, it is redundant as there is no meaningful distinction between a value expression of type `T` and type `const T`. For example, given a type and methods: @@ -803,20 +798,20 @@ meaningful distinction between a value expression of type `T` and type class X { fn Method[self: Self](); fn ConstMethod[self: const Self](); - fn AddrMethod[addr self: Self*](); - fn AddrConstMethod[addr self: const Self*](); + fn RefMethod[ref self: Self](); + fn RefConstMethod[ref self: const Self](); } ``` The methods can be called on different kinds of expressions according to the following table: -| Expression category: | `let x: X`
(value) | `let x: const X`
(const value) | `var x: X`
(reference) | `var x: const X`
(const reference) | -| --------------------: | ------------------------ | ------------------------------------ | ---------------------------- | ---------------------------------------- | -| `x.Method();` | ✅ | ✅ | ✅ | ✅ | -| `x.ConstMethod();` | ✅ | ✅ | ✅ | ✅ | -| `x.AddrMethod();` | ❌ | ❌ | ✅ | ❌ | -| `x.AddrConstMethod()` | ❌ | ❌ | ✅ | ✅ | +| Expression category: | `let x: X`
(value) | `let x: const X`
(const value) | `var x: X`
(reference) | `var x: const X`
(const reference) | +| -------------------: | ------------------------ | ------------------------------------ | ---------------------------- | ---------------------------------------- | +| `x.Method();` | ✅ | ✅ | ✅ | ✅ | +| `x.ConstMethod();` | ✅ | ✅ | ✅ | ✅ | +| `x.RefMethod();` | ❌ | ❌ | ✅ | ❌ | +| `x.RefConstMethod()` | ❌ | ❌ | ✅ | ✅ | The `const T` type has the same representation as `T` with the same field names, but all of its field types are also `const`-qualified. Other than fields, all @@ -859,11 +854,11 @@ and realistic Carbon code patterns that cannot be expressed with the tools in this proposal in order to motivate a minimal extension. Some candidates based on functionality already proposed here or for [classes](/docs/design/classes.md): -- Allow overloading between `addr me` and `me` in methods. This is among the - most appealing as it _doesn't_ have the combinatorial explosion. But it is - also very limited as it only applies to the implicit object parameter. +- Allow overloading between `ref self` and `self` in methods. This is among + the most appealing as it _doesn't_ have the combinatorial explosion. But it + is also very limited as it only applies to the implicit object parameter. - Allow overloading between `var` and non-`var` parameters. -- Expand the `addr` technique from object parameters to all parameters, and +- Expand the `ref` technique from object parameters to all parameters, and allow overloading based on it. Perhaps more options will emerge as well. Again, the goal isn't to completely @@ -927,7 +922,7 @@ will require that the type containing that specifier satisfies the constraint ```carbon interface ReferenceImplicitAs { let T:! type; - fn Convert[addr self: const Self*]() -> T; + fn Convert[ref self: const Self]() -> T; } ``` @@ -972,11 +967,11 @@ class String { private var capacity: i64; impl as ReferenceImplicitAs where .T = StringView { - fn Op[addr self: const Self*]() -> StringView { + fn Op[ref self: const Self]() -> StringView { // Because this is called on the String object prior to it becoming // a value, we can access an SSO buffer or other interior pointers // of `self`. - return StringView.Make(self->data_ptr, self->size); + return StringView.Make(self.data_ptr, self.size); } } @@ -998,8 +993,8 @@ class String { // Note that even though the `Self` type is `const` qualified here, this // cannot be called on a `String` value! That would require us to convert to a // `StringView` that does not track the extra data member. - fn Capacity[addr self: const Self*]() -> i64 { - return self->capacity; + fn Capacity[ref self: const Self]() -> i64 { + return self.capacity; } } ```