[swift-evolution] [Pitch] Add overrides with UnsafePointer sources to non-destructive copying methods on UnsafeMutablePointer

Janosch Hildebrand jnosh at jnosh.com
Tue Feb 2 17:06:42 CST 2016

Hi everyone!

I have a small change to `UnsafeMutablePointer` that I'd like to pitch here before turning it into a full proposal and I'd love to hear your feedback on it.

`UnsafeMutablePointer` offers the following methods to copy memory contents non-destructively:

func assignBackwardFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func assignFrom(source: UnsafeMutablePointer<Pointee>, count: Int)
func initializeFrom(source: UnsafeMutablePointer<Pointee>, count: Int)

Basically my proposal boils down to adding overloads for these methods to `UnsafeMutablePointer` that take `UnsafePointer` source arguments instead.

Currently it is necessary to cast an `UnsafePointer` to `UnsafeMutablePointer` before using it with one of these methods:

let source: UnsafePointer<Int> = ...
let destination: UnsafeMutablePointer<Int> = ...

destination.assignFrom(UnsafeMutablePointer(source), count: count)

I'd like to get rid of these casts. I would argue that they are not only technically unnecessary and add visual noise but that they could actually be a source of confusion.
A cast of an `UnsafePointer` to its mutable variant should throw up a red flag in most cases and even though this case is ultimately innocuous it still increases cognitive load on the reader.


* The obvious alternative is to simply not add these methods. 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.

* One way of working around the overloads would be to, for example, add a `PointerProtocol` to the standard library and make use of that in these methods. However, that would be a much more intrusive change with little immediate (if any) benefit and introduces more questions than it answers.

* Finally, the implicit conversions from `UnsafeMutablePointer<T>` to `UnsafePointer<T>` could be leveraged to work around the need for overloads by dropping the existing methods taking `UnsafeMutablePointer` source arguments. If I had to guess, I'd say that bit of compiler magic probably exists more in service of (Obj)-C interaction and I would be wary to depend on it here. It's also non-obvious from a documentation and auto-completion perspective.

I also have a few related items that might make sense to discuss in tandem while we're talking about `UnsafePointer` and friends.

* func distanceTo(x: Unsafe(Mutable)Pointer<Memory>) -> Int
This is the only other method on `UnsafePointer` and `UnsafeMutablePointer` for which similar overloads might make sense. However, I cannot really see enough of a use case to justify adding overloads here. Also the current methods match protocol requirements whereas the overloads would not.

* UnsafeBufferPointer.init()
One might argue that if we are not going to (a)buse implicit conversions that we should perhaps also add an explicitly overloaded initializer to `UnsafeBufferPointer` that takes an `UnsafeMutablePointer`. I'd agree that is a minor sore point but this is less problematic to begin with and given that one can already use the implicit conversion here I'm not particularly inclined to add this. Also I'd strongly argue against its symmetrical other (an initializer to `UnsafeMutableBufferPointer` taking an `UnsafePointer`).

* `Unsafe(Mutable)Pointer` conversion initializers. 
The generic conversion initializers for `UnsafePointer` and `UnsafeMutablePointer` suffer from a minor type inference deficiency. For example:

let ptr: UnsafeMutablePointer<Int> = nil
let ptr2 = UnsafePointer(ptr) // Error: Cannot invoke initializer for type 'UnsafePointer<_>' with an argument list of type '(UnsafeMutablePointer<Int>)'

In this and similar cases, the compiler cannot currently infer the seemingly obvious choice of retaining the same generic parameter without some additional context.
Technically this could be solved by adding non-generic initializers but that seems like a clutch. This is probably a conscious design decision or at least known limitation with the type inference system and should be addressed there.

- Janosch

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160203/000c941b/attachment.html>

More information about the swift-evolution mailing list