From 21cfcde156204d8485075d4a353a704aaea724e4 Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Fri, 26 Sep 2025 21:47:07 -0600 Subject: [PATCH 1/6] Replace all `addr self` with `ref self` Replaced mechanically. Care is taken to preserve `const` and remove the `*` from the type. This also removes `->` uses of `self` and replaces them with `.`, using the same mechanical tools. --- docs/design/README.md | 26 +++--- docs/design/assignment.md | 31 ++++--- docs/design/classes.md | 26 +++--- docs/design/expressions/member_access.md | 4 +- docs/design/generics/appendix-witness.md | 4 +- docs/design/generics/details.md | 110 +++++++++++------------ docs/design/generics/overview.md | 12 +-- docs/design/generics/terminology.md | 4 +- docs/design/sum_types.md | 4 +- docs/design/templates.md | 4 +- docs/design/values.md | 16 ++-- 11 files changed, 120 insertions(+), 121 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index aef2dc785e6b2..340dec38af2dd 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}; @@ -1797,7 +1797,7 @@ two methods `Distance` and `Offset`: 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 + using `[ref 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). - Methods may be declared lexically inline like `Distance`, or lexically out @@ -1955,7 +1955,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 +1969,7 @@ or: ```carbon class MyClass { // Can modify `self` in the body. - fn destroy[addr self: Self*]() { ... } + fn destroy[ref self: Self]() { ... } } ``` @@ -2996,8 +2996,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 +3008,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 +3043,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..303a46ab954f5 100644 --- a/docs/design/assignment.md +++ b/docs/design/assignment.md @@ -74,8 +74,7 @@ standard library. 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: +`[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..a6c618afe686f 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,7 +925,7 @@ 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 @@ -1585,7 +1585,7 @@ or: ```carbon class MyClass { // Can modify `self` in the body. - fn destroy[addr self: Self*]() { ... } + fn destroy[ref self: Self]() { ... } } ``` @@ -1608,9 +1608,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 +1622,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 +1677,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 +1835,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..acb165e58fd48 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 { @@ -773,7 +773,7 @@ If instance binding is performed: ```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. 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..b41abd62d03a0 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)); 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/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..eddd582833571 100644 --- a/docs/design/values.md +++ b/docs/design/values.md @@ -473,7 +473,7 @@ to the operation in question. For example: ```carbon class S { fn ValueMemberFunction[self: Self](); - fn AddrMemberFunction[addr self: const Self*](); + fn AddrMemberFunction[ref self: const Self](); } fn F(s_value: S) { @@ -803,8 +803,8 @@ 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 AddrMethod[ref self: Self](); + fn AddrConstMethod[ref self: const Self](); } ``` @@ -927,7 +927,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 +972,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 +998,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; } } ``` From 6eac6e346b3bc65ee9cd7df23c70af53cf4be4e4 Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Fri, 26 Sep 2025 21:49:12 -0600 Subject: [PATCH 2/6] Replace special case `self` type in details.md --- docs/design/generics/details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/generics/details.md b/docs/design/generics/details.md index b41abd62d03a0..11a4988efdc11 100644 --- a/docs/design/generics/details.md +++ b/docs/design/generics/details.md @@ -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)](); } ``` From 9c5a73ca2b043b867888b5cc608818e151b94a58 Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Fri, 26 Sep 2025 21:55:24 -0600 Subject: [PATCH 3/6] Replace remaining `addr` keywords with `ref` manually --- docs/design/README.md | 4 ++-- docs/design/classes.md | 2 +- docs/design/expressions/member_access.md | 2 +- docs/design/lambdas.md | 2 +- docs/design/lexical_conventions/words.md | 2 +- docs/design/values.md | 24 ++++++++++++------------ 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index 340dec38af2dd..e96d8a7812ebb 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -2004,8 +2004,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)*`. diff --git a/docs/design/classes.md b/docs/design/classes.md index a6c618afe686f..1d236ae943097 100644 --- a/docs/design/classes.md +++ b/docs/design/classes.md @@ -927,7 +927,7 @@ Assert(Math.Abs(c.Diameter() - 4.0) < 0.001); - `c.Expand(`...`)` does modify the value of `c`. This is signified using `[ref self: Self]` in the method declaration. -The pattern '`addr self:` _type_' means "first take the address of the argument, +The pattern '`ref self:` _type_' means "first take the address of the argument, which must be an [l-value](), and then match pattern '`self:` _type_' against it". diff --git a/docs/design/expressions/member_access.md b/docs/design/expressions/member_access.md index acb165e58fd48..c26639e371283 100644 --- a/docs/design/expressions/member_access.md +++ b/docs/design/expressions/member_access.md @@ -767,7 +767,7 @@ If instance binding is performed: 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 + - If the method declares its `self` parameter with `ref`, the recipient argument is `&x`. - Otherwise, the recipient argument is `x`. 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/values.md b/docs/design/values.md index eddd582833571..14749b58126f0 100644 --- a/docs/design/values.md +++ b/docs/design/values.md @@ -264,9 +264,9 @@ _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. +where the method's `self` parameter has an `ref` 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 @@ -312,15 +312,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 @@ -794,7 +794,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: @@ -859,11 +859,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 From 187a7cb08f3dd0550f3ebba52f19b5e9d0ff56b0 Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Fri, 26 Sep 2025 21:58:47 -0600 Subject: [PATCH 4/6] Tidy up some function names in values.md These functions used to refer to the `addr` keyword in their names. --- docs/design/values.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/design/values.md b/docs/design/values.md index 14749b58126f0..156d541061962 100644 --- a/docs/design/values.md +++ b/docs/design/values.md @@ -473,7 +473,7 @@ to the operation in question. For example: ```carbon class S { fn ValueMemberFunction[self: Self](); - fn AddrMemberFunction[ref self: const Self](); + fn RefMemberFunction[ref self: const Self](); } fn F(s_value: S) { @@ -481,7 +481,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(); } ``` @@ -803,20 +803,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[ref self: Self](); - fn AddrConstMethod[ref 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 From cfa775dc117e7ca2cee3b62e0066d57d959a98c8 Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Fri, 26 Sep 2025 23:04:55 -0600 Subject: [PATCH 5/6] Update surrounding text --- docs/design/README.md | 7 +++---- docs/design/classes.md | 7 +++---- docs/design/values.md | 5 ----- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index e96d8a7812ebb..78b3f7d74f27e 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -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 `[ref 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`. diff --git a/docs/design/classes.md b/docs/design/classes.md index 1d236ae943097..1efdf4a278fbf 100644 --- a/docs/design/classes.md +++ b/docs/design/classes.md @@ -927,10 +927,9 @@ Assert(Math.Abs(c.Diameter() - 4.0) < 0.001); - `c.Expand(`...`)` does modify the value of `c`. This is signified using `[ref self: Self]` in the method declaration. -The pattern '`ref 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), diff --git a/docs/design/values.md b/docs/design/values.md index 156d541061962..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 `ref` 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. From 56f64a56bb341261fbe2f9773fee598f98891dab Mon Sep 17 00:00:00 2001 From: Calvin Watford Date: Mon, 29 Sep 2025 20:52:05 -0600 Subject: [PATCH 6/6] Add suggestions from review comments --- docs/design/assignment.md | 2 +- docs/design/expressions/member_access.md | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/design/assignment.md b/docs/design/assignment.md index 303a46ab954f5..a8f7ee6a0f480 100644 --- a/docs/design/assignment.md +++ b/docs/design/assignment.md @@ -73,7 +73,7 @@ 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 +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. diff --git a/docs/design/expressions/member_access.md b/docs/design/expressions/member_access.md index c26639e371283..8d8a51ffff0ad 100644 --- a/docs/design/expressions/member_access.md +++ b/docs/design/expressions/member_access.md @@ -765,11 +765,7 @@ 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 `ref`, the recipient - argument is `&x`. - - Otherwise, the recipient argument is `x`. + `self` parameter initialized by `x`. ```carbon class Blob { @@ -777,7 +773,7 @@ If instance binding is performed: } 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);