func mutates(_ x: UnsafeMutablePointer<Int>) { ... }
func doesntMutate(_ x: UnsafePointer<Int>) { ... }
func bar(x: Int, y: Int) {
mutates(&x) // 🛑 Cannot pass immutable value as inout argument:
// 'x' is a 'let' constant 😀👍
var x = x
mutates(&x) // ✅ 😀👍
doesntMutate(&y) // 🛑 same error?! 😒👎
var y = y // feels odd I need this 😒👎
doesntMutate(&y) // ✅
}
I would understand the error if "doesntMutate" was taking "UnsafeMutablePointer" but here it takes "UnsafePointer" and it is not possible to modify the passed argument anyway. It feels that I have to make a copy for no good reason, which might be trivial for Int, but for String / Array / etc there's a not so trivial cost even taking into account the COW optimisation (and some value types won't have COW optimisation!).
The & operator is not a pointer-to operator, it's an inout operator, and separately there's an inout-to-pointer conversion that converts an inout parameter to a mutable pointer. There's a valid argument to be made that Swift should add this capability, but you can accomplish what you want using the built-in withUnsafePointer function.
withUnsafePointer(to: y) { pointerToY in
doesntMutate(pointerToY)
}
With SE-377 we could mark the to parameter of withUnsafePointer with borrowing, but borrowing is already the implicit ownership for that parameter. If internally withUnsafePointer does something that requires a copy of its parameter then that's unfortunate.
As an optimization the compiler may sometimes pass a borrowing argument by-value when the type is copyable and simple, like Int. But because withUnsafePointer<T> is generic over its to parameter, it's always going to pass an address; the borrowing ownership just prevents the caller from having to retain/copy the value before the address is formed.
I do not think it is a good idea to allow implicit casts of &var to an unsafe type like UnsafeMutablePointer.