Why is UnsafePointer(bitPattern: ) failable?

Looking at the documentation of this initializer:

/// Creates a new raw pointer from the given address, specified as a bit
/// pattern.
/// - Parameter bitPattern: A bit pattern to use for the address of the new
///   raw pointer. If `bitPattern` is zero, the result is `nil`.
public init?(bitPattern: Int)

I understand exactly what it says, but it fails to explain why it has to be a failable initializer, and why it should return nil when bitPattern is zero.

I mean, we can still successfully compile and run eg:

let p = UnsafeMutableRawPointer.init(bitPattern: 1)! - 1
print(p) // 0x0000000000000000

This is of course unsafe, just like a lot of other things you can do with unsafe pointers (hence the naming), so what is this initializer trying to protect me from?

It’s perfectly happy to let me use the bitPattern -1, resulting in the address being UInt64.max:

let p = UnsafeMutableRawPointer.init(bitPattern: -1)!
print(p) // 0xffffffffffffffff

Is it failable and nil for the zero bit pattern because of something that has to do with NULL in C interop or something?

Remember that nil is the representation of a null pointer, but at the same time people pass null pointers through uintptr_t fields sometimes. So the initializer isn’t trying to protect you; it’s just doing the same thing that C does when you say (void *)bitPattern. (If I wanted to be more explicit, I could say (void * _Nullable)bitPattern. ;-) )

As you discovered, you can form a non-Optional UnsafePointer with an address of 0 if you really try. However, you’re likely to run afoul of optimizations that assume things about optional and non-optional pointers if you do, so I don’t recommend it.

1 Like

Thanks, a related question: I think I read somewhere that bindMemory is zero overhead (because it’s just info for the compiler) but I guess that force unwrapping an optional UnsafeMutableRawPointer might induce a performance overhead, as in eg

rawCellData!.advanced(by: (cellIndex &<< 9) &+ ((1 &+ particleCount) &<< 5))
    .bindMemory(to: Particle.self, capacity: 1).pointee = addedParticle

compared to if rawCellData is not an optional pointer:

rawCellData.advanced(by: (cellIndex &<< 9) &+ ((1 &+ particleCount) &<< 5))
    .bindMemory(to: Particle.self, capacity: 1).pointee = addedParticle

assuming it is not possible for the compiler to know whether (the top version’s) rawCellData is nil or not?

(This is from a single swift file that contains a very low-level implementation of an algorithm/data structure, built using only private top level functions that manipulates some data pointed to by the private top level UnsafeMutableRawPointer rawCellData.

There are also a couple of module-internal functions in that file, forming its “interface”, eg:

func createCellData() { … }
func performSomeComputation(…) -> … { … }
func shutDownCellData() { … }

It’s built this way because I’m going to compare it to a more high level implementation of the same algorithm/data structure.)

There is always the unsafelyUnwrapped property if you absolutely need to skip the null check.

1 Like

Ah, I had forgot about that, thanks!