[swift-evolution] Making pointer nullability explicit (using Optional)

Brent Royal-Gordon brent at architechies.com
Fri Mar 18 20:23:45 CDT 2016


> The main thing is just that UnsafeBufferPointer doesn't act like a pointer; it acts like a buffer, and a zero-element buffer turns out to be a perfectly useful degenerate case (and something that will happen anyway for an array with capacity reserved but no elements). In the cases where you use it as a Collection, nothing cares whether the base pointer is null.

If UnsafeBufferPointer is primarily a buffer, not a pointer, then I think it's okay for the base address to be optional.

(And maybe it should just be called `UnsafeBuffer`.)

I really hate the "just make up an address" solution because the address is only "valid" in the narrow, technical sense that it's properly aligned and perhaps in an allocated page. In an empty buffer, it is never valid to actually *access* the memory at that address. There is no data there, so you have no business trying to do anything with the memory at that address.

If the buffer base address is nil, the situation is accurately represented: no memory has been allocated to store this buffer's contents. If the buffer base address is some random pointer, the buffer is telling a dangerous lie.

So I think the only way to make UnsafeBufferPointer accurately represent the situation is with either 2i (optional okay, base address of empty buffers can be arbitrary) or 2ii (optional okay, base address of empty buffers must be nil). There's a certain appeal to 2ii, but I think 2i is probably more useful. I could imagine somebody constructing an UnsafeBufferPointer that represents a slice of the actual buffer; in that case, there really *is* a buffer at that memory address, it's just that your slice of it doesn't have any elements. And the ability to construct a larger buffer from a zero-sized one might be useful.

Actually, I could make an argument for a design like this:

	public struct UnsafeBufferPointer<Element> {
		public init(baseAddress: UnsafePointer<Element>?, count: Int)
		
		private var _baseAddress: UnsafePointer<Element>?
		
		/// -Precondition: the base address provided at construction was not `nil`.
		public var baseAddress: UnsafePointer<Element> {
			return _baseAddress!
		}
		
		// Use these methods to safely modify a buffer pointer whether or not it has a base address.
		func rebased(at newBasePointer: UnsafePointer<Element>?) -> UnsafeBufferPointer
		func resized(to count: Int) -> UnsafeBufferPointer
	}

Or even a design that used an auto-unwrapped Optional. But with the same behavior just an `!` away, I don't think that's a good idea.

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list