Skip to content

Commit 02fc95a

Browse files
committed
Rename Array to ContiguousArray.
The examples all refer to a `span()` function. This is unimplementable for `Array` because it might not have contiguous storage. An `Array` span requires a `_read` accessor because we need to create a temporary copy of the Array when it is discontiguous. But we can't talk about `_read` here because it hasn't been proposed yet.
1 parent b01cd1e commit 02fc95a

File tree

1 file changed

+21
-21
lines changed

1 file changed

+21
-21
lines changed

proposals/NNNN-lifetime-dependency.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ This is a key requirement for the `Span` type (previously called `BufferView`) b
4747
An efficient way to provide one piece of code with temporary access to data stored in some other piece of code is with a pointer to the data in memory.
4848
Swift's `Unsafe*Pointer` family of types can be used here, but as the name implies, using these types can be error-prone.
4949

50-
For example, suppose `Array` had a property `unsafeBufferPointer` that returned an `UnsafeBufferPointer` to the contents of the array.
50+
For example, suppose `ContiguousArray` had a property `unsafeBufferPointer` that returned an `UnsafeBufferPointer` to the contents of the array.
5151
Here's an attempt to use such a property:
5252

5353
```swift
54-
let array = getArrayWithData()
54+
let array = getContiguousArrayWithData()
5555
let buff = array.unsafeBufferPointer
5656
parse(buff) // <== 🛑 NOT SAFE!
5757
```
@@ -111,11 +111,11 @@ In the most common cases, these constraints can be inferred automatically.
111111

112112
To make the semantics clearer, we’ll begin by describing how one can explicitly specify a lifetime constraint in cases where the default inference rules do not apply.
113113

114-
Let’s consider adding support for our hypothetical `Span` type to `Array`.
114+
Let’s consider adding support for our hypothetical `Span` type to `ContiguousArray`.
115115
Our proposal would allow you to declare an `array.span()` method as follows:
116116

117117
```swift
118-
extension Array {
118+
extension ContiguousArray {
119119
borrowing func span() -> dependsOn(self) Span<Element> {
120120
... construct a Span ...
121121
}
@@ -138,7 +138,7 @@ Let’s consider another hypothetical type: a `MutatingSpan<T>` type that could
138138
Here's one way such a value might be produced:
139139

140140
```swift
141-
func mutatingSpan(to: inout Array, count: Int) -> dependsOn(to) MutatingSpan<Element> {
141+
func mutatingSpan(to: inout ContiguousArray, count: Int) -> dependsOn(to) MutatingSpan<Element> {
142142
... construct a MutatingSpan ...
143143
}
144144
```
@@ -153,7 +153,7 @@ Similar to the previous example:
153153

154154
In both this and the previous case, the lifetime of the return value is "scoped" to the lifetime of the original value.
155155
Because lifetime dependencies can only be attached to nonescapable values, types that contain pointers will generally need to be nonescapable in order to provide safe semantics.
156-
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as an Array or similar container) is providing a nonescapable value (such as the `Span` or `MutatingSpan` in these examples).
156+
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as a ContiguousArray or similar container) is providing a nonescapable value (such as the `Span` or `MutatingSpan` in these examples).
157157

158158
#### Copied Lifetime Dependency
159159

@@ -176,7 +176,7 @@ If the original `Span` was borrowing some array, the new `Span` will continue to
176176

177177
This supports coding patterns such as this:
178178
```swift
179-
let a: Array<Int>
179+
let a: ContiguousArray<Int>
180180
let ref1 = a.span() // ref1 cannot outlive a
181181
let ref2 = ref1.drop(4) // ref2 also cannot outlive a
182182
```
@@ -317,9 +317,9 @@ extension Span {
317317
We've discussed how a nonescapable result must be destroyed before the source of its lifetime dependence. Similarly, a dependent argument must be destroyed before an argument that it depends on. The difference is that the dependent argument may already have a lifetime dependence when it enters the function. The new function argument dependence is additive, because the call does not guarantee reassignment. Instead, passing the 'inout' argument is like a conditional reassignment. After the function call, the dependent argument carries both lifetime dependencies.
318318

319319
```swift
320-
let a1: Array<Int> = ...
320+
let a1: ContiguousArray<Int> = ...
321321
var span = a1.span()
322-
let a2: Array<Int> = ...
322+
let a2: ContiguousArray<Int> = ...
323323
mayReassign(span: &span, to: a2)
324324
// 'span' now depends on both 'a1' and 'a2'.
325325
```
@@ -680,10 +680,10 @@ If a function, method, or initializer has a nonescapable return value, does not
680680

681681
### Dependency semantics by example
682682

683-
This section illustrates the semantics of lifetime dependence one example at a time for each interesting variation. The following helper functions will be useful: `Array.span()` creates a scoped dependence to a nonescapable `Span` result, `copySpan()` creates a copied dependence to a `Span` result, and `parse` uses a `Span`.
683+
This section illustrates the semantics of lifetime dependence one example at a time for each interesting variation. The following helper functions will be useful: `ContiguousArray.span()` creates a scoped dependence to a nonescapable `Span` result, `copySpan()` creates a copied dependence to a `Span` result, and `parse` uses a `Span`.
684684

685685
```swift
686-
extension Array {
686+
extension ContiguousArray {
687687
// The returned span depends on the scope of Self.
688688
borrowing func span() -> /* dependsOn(scoped self) */ Span<Element> { ... }
689689
}
@@ -697,7 +697,7 @@ func parse(_ span: Span<Int>) { ... }
697697
#### Scoped dependence on an immutable variable
698698

699699
```swift
700-
let a: Array<Int> = ...
700+
let a: ContiguousArray<Int> = ...
701701
let span: Span<Int>
702702
do {
703703
let a2 = a
@@ -715,7 +715,7 @@ Let's contrast scoped dependence shown above with copied dependence on a variabl
715715
An assignment that copies or moves a nonescapable value from one variable into another **copies** any lifetime dependence from the source value to the destination value. Thus, variable assignment has the same lifetime copy semantics as passing an argument using a `dependsOn()` annotation *without* a `scoped` keyword. So, the statement `let temp = span` has identical semantics to `let temp = copySpan(span)`.
716716

717717
```swift
718-
let a: Array<Int> = arg
718+
let a: ContiguousArray<Int> = arg
719719
let final: Span<Int>
720720
do {
721721
let span = a.span()
@@ -746,7 +746,7 @@ extension Span {
746746
A dependence may be copied from a mutable ('inout') variable. In that case, the dependence is inherited from whatever value the mutable variable holds when it is accessed.
747747

748748
```swift
749-
let a: Array<Int> = ...
749+
let a: ContiguousArray<Int> = ...
750750
var prefix: Span<Int>
751751
do {
752752
var temp = a.span()
@@ -761,7 +761,7 @@ parse(prefix) // ✅ Safe: still within lifetime of 'a'
761761
Now, let's return to scoped dependence, this time on a mutable variable. This is where exclusivity guarantees come into play. A scoped depenendence extends an access of the mutable variable across all uses of the dependent value. If the variable mutates again before the last use of the dependent, then it is an exclusivity violation.
762762

763763
```swift
764-
let a: Array<Int> = ...
764+
let a: ContiguousArray<Int> = ...
765765
a[i] = ...
766766
let span = a1.span()
767767
parse(span) // ✅ Safe: still within 'span's access on 'a'
@@ -777,7 +777,7 @@ We've described how a mutable variable can be the source of a lifetime dependenc
777777

778778
```swift
779779
func reassign(_ span: inout Span<Int>) {
780-
let a: Array<Int> = ...
780+
let a: ContiguousArray<Int> = ...
781781
span = a.span() // 🛑 Error: 'span' escapes the scope of 'a'
782782
}
783783
```
@@ -797,9 +797,9 @@ func reassignWithArgDependence(_ span: dependsOn(arg) inout [Int], _ arg: [Int])
797797
'inout' argument dependence behaves like a conditional reassignment. After the call, the variable passed to the 'inout' argument has both its original dependence along with a new dependence on the argument that is the source of the argument dependence.
798798

799799
```swift
800-
let a1: Array<Int> = arg
800+
let a1: ContiguousArray<Int> = arg
801801
do {
802-
let a2: Array<Int> = arg
802+
let a2: ContiguousArray<Int> = arg
803803
var span = a1.span()
804804
testReassignArgDependence(&span, a2) // creates a conjoined dependence
805805
parse(span) // ✅ OK: within the lifetime of 'a1' & 'a2'
@@ -850,21 +850,21 @@ We propose above putting the annotation on the return value, which we believe ma
850850
It would also be possible to put an annotation on the parameters instead:
851851

852852
```swift
853-
func f(@resultDependsOn arg1: Array<Int>) -> Span<Int>
853+
func f(@resultDependsOn arg1: ContiguousArray<Int>) -> Span<Int>
854854
```
855855

856856
Depending on the exact language in use, it could also be more natural to put the annotation after the return value.
857857
However, we worry that this hides this critical information in cases where the return type is longer or more complex.
858858

859859
```swift
860-
func f(arg1: Array<Int>) -> Span<Int> dependsOn(arg1)
860+
func f(arg1: ContiguousArray<Int>) -> Span<Int> dependsOn(arg1)
861861
```
862862

863863
### Different spellings
864864

865865
An earlier version of this proposal advocated using the existing `borrow`/`mutate`/`consume`/`copy` keywords to specify a particular lifetime dependency semantic:
866866
```swift
867-
func f(arg1: borrow Array<Int>) -> borrow(arg1) Span<Int>
867+
func f(arg1: borrow ContiguousArray<Int>) -> borrow(arg1) Span<Int>
868868
```
869869
This was changed after we realized that there was in practice almost always a single viable semantic for any given situation, so the additional refinement seemed unnecessary.
870870

0 commit comments

Comments
 (0)