Skip to content

Commit 4882ef9

Browse files
committed
Fix small oversights in Hypoarray example code
1 parent d3de16e commit 4882ef9

File tree

1 file changed

+15
-12
lines changed

1 file changed

+15
-12
lines changed

proposals/XXXX-noncopyable-stdlib-primitives.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,13 +1536,16 @@ When the array is destroyed, we need to properly deinitialize its elements and d
15361536

15371537
Note the use of the new `extracting` operation to get a buffer pointer that consists of just the slots that have been populated. We cannot call `_storage.deinitialize()` as it isn't necessarily fully initialized; and we also cannot use the classic slicing operation `_storage[..<count]`, as it would need to return a `Slice`, and that type doesn't support noncopyable elements.
15381538

1539-
Hypoarrays can be declared sendable when their element type is sendable.
1539+
Hypoarrays can be declared sendable when their element type is sendable.
15401540

15411541
```swift
1542-
extension Hypoarray: Sendable where Element: Sendable & ~Copyable {}
1542+
extension Hypoarray: @unchecked Sendable
1543+
where Element: Sendable & ~Copyable {}
15431544
```
15441545

1545-
We need to remember to suppress the copyability of `Element`. If we forgot that, then this conditional sendability would only apply if `Element` happened to be copyable.
1546+
`Hypoarray` relies on unsafe pointer operations and dynamic memory allocation to implement its storage, so the compiler is not able to prove that it'll be correctly sendable. The `@unchecked` attribute acknowledges this and promises that the type is still following the rules of sendability.
1547+
1548+
We need to remember to suppress the copyability of `Element`. If we forgot that, then this conditional sendability would only apply if `Element` happened to be copyable.
15461549

15471550
Of course, an array needs to provide access to its contents, and it also needs operations to add and remove elements. The task of inventing variants of the `Sequence` and `Collection` protocols that allow noncopyable conforming types and element types is deferred to a subsequent proposal, but we can safely expect that even generalized array types will be based on the concept of an integer index, and that the existing indexing operations in `Collection` will largely translate into the noncopyable universe:
15481551

@@ -1587,7 +1590,7 @@ extension Hypoarray where Element: ~Copyable {
15871590
return try body(_storage[index])
15881591
}
15891592

1590-
mutating func modifyElement<E: Error, R: ~Copyable> (
1593+
mutating func updateElement<E: Error, R: ~Copyable> (
15911594
at index: Int,
15921595
by body: (inout Element) throws(E) -> R
15931596
) throws(E) -> R {
@@ -1602,7 +1605,7 @@ These are quite clumsy, but they do work safely, and they provide in-place borro
16021605
```swift
16031606
// Example usage:
16041607
var array = Hypoarray<Int>(42)
1605-
array.modifyElement(at: 0) { $0 += 1 }
1608+
array.updateElement(at: 0) { $0 += 1 }
16061609
array.borrowElement(at: 0) { print($0) } // Prints "43"
16071610
```
16081611

@@ -1613,12 +1616,12 @@ array.borrowElement(at: 0) { print($0) } // Prints "43"
16131616
extension Hypoarray where Element: ~Copyable {
16141617
subscript(position: Int) -> Element {
16151618
read {
1616-
precondition(index >= 0 && index < _count)
1617-
try yield _storage[index]
1619+
precondition(position >= 0 && position < _count)
1620+
try yield _storage[position]
16181621
}
16191622
modify {
1620-
precondition(index >= 0 && index < _count)
1621-
try yield &_storage[index]
1623+
precondition(position >= 0 && position < _count)
1624+
try yield &_storage[position]
16221625
}
16231626
}
16241627
}
@@ -1639,13 +1642,13 @@ It would be desirable to allow iteration over `Hypoarray` instances. Unfortunate
16391642
// Example usage:
16401643
var array: Hypoarray<Int> = ...
16411644
for i in array.startIndex ..< array.endIndex { // a.k.a. 0 ..< array.count
1642-
array.readElement(at: i) { print($0) }
1645+
array.borrowElement(at: i) { print($0) }
16431646
}
16441647
```
16451648

16461649
Not having noncopyable container protocols also means that `Hypoarray` cannot conform to any, so subsequently it will not get any of the standard generic container algorithms for free: there is no `firstIndex(of:)`, there is no `map`, no `filter`, no slicing, no `sort`, no `reverse`. Indeed, many of these standard algorithms expect to work on `Equatable` or `Comparable` items, and those protocols are also yet to be generalized.
16471650

1648-
Okay, so all we have is `readElement` and `modifyElement`, for borrowing and mutating access. What about consuming access, though?
1651+
Okay, so all we have is `borrowElement` and `updateElement`, for borrowing and mutating access. What about consuming access, though?
16491652

16501653
Consuming an item of an array at a particular index would require either removing the item from the array, or destroying and discarding the rest of the array. Neither of these looks desirable as a primitive operation for accessing an element. However, we do expect arrays to provide a named operation for removing items, `remove(at:)`. This operation is easily implementable on `Hypoarray`:
16511654

@@ -1693,7 +1696,7 @@ We want insertions to have amortized O(1) complexity, so they need to be careful
16931696

16941697
```swift
16951698
extension Hypoarray where Element: ~Copyable {
1696-
internal func _ensureFreeCapacity(_ minimumCapacity: Int) {
1699+
mutating func _ensureFreeCapacity(_ minimumCapacity: Int) {
16971700
guard capacity < _count + minimumCapacity else { return }
16981701
reserveCapacity(max(_count + minimumCapacity, 2 * capacity))
16991702
}

0 commit comments

Comments
 (0)