<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 18, 2016, at 9:49 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 17, 2016, at 21:08 , Russ Bishop <<a href="mailto:xenadu@gmail.com" class="">xenadu@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I’m very much +1 on this idea.</div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 17, 2016, at 6:59 PM, Jordan Rose via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div></blockquote><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><h3 style="box-sizing: border-box; margin-top: 1em; margin-bottom: 16px; line-height: 1.43; font-size: 1.5em; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; background-color: rgb(255, 255, 255);" class=""><a id="user-content-open-issue-unsafebufferpointer" class="anchor" href="https://github.com/jrose-apple/swift-evolution/tree/optional-pointers#open-issue-unsafebufferpointer" aria-hidden="true" style="box-sizing: border-box; background-color: transparent; color: rgb(64, 120, 192); text-decoration: none; display: inline-block; padding-right: 2px; margin-left: -18px; line-height: 1.2;"><svg aria-hidden="true" class="octicon octicon-link" height="16" role="img" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1h-1c-1.5 0-3-1.69-3-3.5s1.55-3.5 3-3.5h4c1.45 0 3 1.69 3 3.5 0 1.41-0.91 2.72-2 3.25v-1.16c0.58-0.45 1-1.27 1-2.09 0-1.28-1.02-2.5-2-2.5H4c-0.98 0-2 1.22-2 2.5s1 2.5 2 2.5z m9-3h-1v1h1c1 0 2 1.22 2 2.5s-1.02 2.5-2 2.5H9c-0.98 0-2-1.22-2-2.5 0-0.83 0.42-1.64 1-2.09v-1.16c-1.09 0.53-2 1.84-2 3.25 0 1.81 1.55 3.5 3 3.5h4c1.45 0 3-1.69 3-3.5s-1.5-3.5-3-3.5z"></path></svg></a>Open Issue: UnsafeBufferPointer</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">The type <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">UnsafeBufferPointer</code> represents a bounded typed memory region with no ownership or lifetime semantics; it is logically a bare typed pointer (its <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">baseAddress</code>) and a length (<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">count</code>). For a buffer with 0 elements, however, there's no need to provide the address of allocated memory, since it can't be read from. Previously this case would be represented as a <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">nil</code> base address and a count of 0.</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">With optional pointers, this now imposes a cost on clients that want to access the base address: they need to consider the <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">nil</code> case explicitly, where previously they wouldn't have had to. There are several possibilities here, each with their own possible implementations:</p><ol style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class=""><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">Like UnsafePointer, UnsafeBufferPointer should always have a valid base address, even when the count is 0. An UnsafeBufferPointer with a potentially-nil base address should be optional.</p><ol style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 0px; list-style-type: lower-roman;" class=""><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer accepts an optional pointer and becomes failable, returning <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">nil</code> if the input pointer is nil.</p></li><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer accepts an optional pointer and synthesizes a non-null aligned pointer value if given nil as a base address.</p></li><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer only accepts non-optional pointers. Clients such as <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">withUnsafeBufferPointer</code>must synthesize a non-null aligned pointer value if they do not have a valid pointer to provide.</p></li><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer only accepts non-optional pointers. Clients <em style="box-sizing: border-box;" class="">using</em> <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">withUnsafeBufferPointer</code>must handle a nil buffer.</p></li></ol></li><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer should allow nil base addresses, i.e. the <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">baseAddress</code> property will be optional. Clients will need to handle this case explicitly.</p><ol style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 0px; list-style-type: lower-roman;" class=""><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer accepts an optional pointer, but no other changes are made.</p></li><li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;" class="">UnsafeBufferPointer's initializer accepts an optional pointer. Additionally, any buffers initialized with a count of 0 will be canonicalized to having a base address of nil.</p></li></ol></li></ol><blockquote style="box-sizing: border-box; margin: 0px 0px 16px; padding: 0px 15px; color: rgb(119, 119, 119); border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class=""><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;" class="">I'm currently leaning towards option (2i). Clients that expect a pointer and length probably shouldn't require the pointer to be non-null, but if they do then perhaps there's a reason for it. It's also the least work.</p><div style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px;" class="">Chris (Lattner) is leaning towards option (1ii), which treats UnsafeBufferPointer similar to UnsafePointer while not penalizing the common case of <code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">withUnsafeBufferPointer</code>.</div></blockquote></div></div></div></blockquote>What’s the use of an UnsafeBufferPointer with zero count? Semantically that is making a claim that it can’t back up (“I have allocated memory at location X” which isn’t compatible with the idea of “zero count/size").</div><div class=""><br class=""></div><div class="">Without knowing more context I’d strongly favor (1i). If an array is empty the natural expectation for withUnsafeBufferPointer is you get UnsafeBufferPointer<Element>? = nil, which follows the behavior of the rest of the language and things like guard let make it trivial to handle properly. If someone really has a problem with it they can add ifUnsafeBufferPointer() that returns a non-optional pointer and skips executing the closure if the Array is empty (which is the behavior of your standard for loop).<br class=""></div></div></div></blockquote><br class=""></div><div class="">The important use case here is that "array.withUnsafeBufferPointer" should always do <i class="">something</i> (i.e. it usually can't just skip the closure)<i class="">,</i> and it turns out it's easiest if the zero-element case is treated the same as everything else. When converting over the standard library I found that very few of them wanted to do something different in the zero-element case, and then it would be bad to force Array to allocate memory just to not use it. That is, there aren't actually any clients interested in knowing whether the base address is valid, and all of the ones that <i class="">do</i> have to think about it (because they use it directly) aren't getting any value out of it.</div><div class=""><br class=""></div><div class="">Jordan</div></div></div></blockquote></div><br class=""><div class="">Does optional chaining (ptr?.count ?? 0) or the guard check (guard let ptr = ptr else { return }) impose a performance (or cognitive) burden here? I’m OK with (2i), it just seems less Swift-ish than (1i). </div><div class=""><br class=""></div><div class="">I don’t use UnsafeBufferPointer a lot so I’ll happily live with whatever the choice is.</div><div class=""><br class=""></div><div class="">Russ</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div></body></html>