SE-0076: Add overrides taking an UnsafePointer source to non-destructive copying methods on UnsafeMutablePointer
* Proposal: [SE-0076](0076-copying-to-unsafe-mutable-pointer-with-unsafe-pointer-source.md) * Author: [Janosch Hildebrand](https://github.com/Jnosh) * Review Manager: [Chris Lattner](https://github.com/lattner) * Status: **Implemented (Swift 3.0)** * Decision Notes: [Rationale](https://forums.swift.org/t/accepted-with-revision-se-0076-add-overrides-taking-an-unsafepointer-source-to-non-destructive-copying-methods-on-unsafemutablepointer/2577) * Bug: [SR-1490](https://bugs.swift.org/browse/SR-1490)
Introduction
UnsafeMutablePointer includes several methods to non-destructively copy elements from memory pointed to by another UnsafeMutablePointer instance. I propose adding overloads of these methods to UnsafeMutablePointer that allow an UnsafePointer source.
Swift-evolution thread: [\[Pitch\] Add overrides with UnsafePointer sources to non-destructive copying methods on UnsafeMutablePointer](https://forums.swift.org/t/pitch-add-overrides-with-unsafepointer-sources-to-non-destructive-copying-methods-on-unsafemutablepointer/1294)
Motivation
To copy values from memory pointed to by an UnsafePointer it is currently necessary to perform a cast to UnsafeMutablePointer beforehand:
let source: UnsafePointer<Int> = ...
let destination: UnsafeMutablePointer<Int> = ...
// Today:
destination.assignFrom(UnsafeMutablePointer(source), count: count)These casts are unnecessary visual noise as non-destructively copying from an UnsafePointer source is perfectly safe. Furthermore, these casts are a source of confusion and increased cognitive load on a reader since any such cast is likely to throw up a red flag at first.
Proposed solution
In addition to these existing methods on UnsafeMutablePointer:
func assignBackwardFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func assignFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func initializeFrom(source: UnsafeMutablePointer<Pointee>, count: Int)I propose adding the following overloads:
func assignBackwardFrom(source: UnsafePointer<Pointee>, count: Int)
func assignFrom(source: UnsafePointer<Pointee>, count: Int)
func initializeFrom(source: UnsafePointer<Pointee>, count: Int)This would transform the given example as follows:
let source: UnsafePointer<Int> = ...
let destination: UnsafeMutablePointer<Int> = ...
// Today:
destination.assignFrom(UnsafeMutablePointer(source), count: count)
// This proposal:
destination.assignFrom(source, count: count)Detailed design
The following methods are added to UnsafeMutablePointer:
/// Assign from `count` values beginning at source into initialized
/// memory, proceeding from the first element to the last.
public func assignFrom(source: UnsafePointer<Pointee>, count: Int)
/// Assign from `count` values beginning at `source` into
/// initialized memory, proceeding from the last value to the first.
/// Use this for assigning ranges into later memory that may overlap
/// with the source range.
///
/// - Requires: Either `source` precedes `self` or follows `self + count`.
public func assignBackwardFrom(source: UnsafePointer<Pointee>, count: Int)
/// Copy `count` values beginning at source into raw memory.
///
/// - Precondition: The memory is not initialized.
///
/// - Requires: `self` and `source` may not overlap.
public func initializeFrom(source: UnsafePointer<Pointee>, count: Int)Impact on existing code
This proposal is additive and does not impact existing code.
Alternatives considered
- Keep the status quo: I'd argue that they provide enough benefit to justify their existence while only minimally increasing the stdlib surface area, especially by merit of being overloads.
- Introduce a
PointerProtocolprotocol: A common protocol could be used to avoid the need for overloads in this case. However, without additional use cases this seems like severe over-engineering for this simple issue. This would also require a lot more design work, performance considerations, etc...
- Leverage implicit conversions: The implicit conversions from
UnsafeMutablePointertoUnsafePointercould be leveraged to work around the need for overloads by dropping the existing methods takingUnsafeMutablePointersource arguments. Adding explicit overloads seems a better solution than depending on compiler magic and is clearer from a documentation and auto-completion perspective.