<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jul 14, 2017 at 12:22 AM, Andrew Trick <span dir="ltr">&lt;<a href="mailto:atrick@apple.com" target="_blank">atrick@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><br><div><div><div class="gmail-h5"><blockquote type="cite"><div>On Jul 13, 2017, at 6:55 PM, Taylor Swift &lt;<a href="mailto:kelvin13ma@gmail.com" target="_blank">kelvin13ma@gmail.com</a>&gt; wrote:</div><br class="gmail-m_-7063113598670509009Apple-interchange-newline"><div><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 13, 2017 at 6:56 PM, Andrew Trick <span dir="ltr">&lt;<a href="mailto:atrick@apple.com" target="_blank">atrick@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><br><div><blockquote type="cite"><span><div>On Jul 12, 2017, at 12:16 PM, Taylor Swift via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br class="gmail-m_-7063113598670509009m_7627022841191771449Apple-interchange-newline"></span><div><div class="gmail-m_-7063113598670509009h5"><div><div dir="ltr"><p>Hi all, I’ve written up a proposal to modify the unsafe pointer API for greater consistency, safety, and ease of use.</p><p>~~~<br></p><p>Swift currently offers two sets of pointer types — singular pointers such as <code>UnsafeMutablePointer</code>, and vector (buffer) pointers such as <code>UnsafeMutable</code><b><code>Buffer</code></b><code>Pointer</code>. This implies a natural separation of tasks the two kinds of pointers are meant to do. For example, buffer pointers implement <code>Collection</code> conformance, while singular pointers do not.</p><p>However, some aspects of the pointer design contradict these implied 
roles. It is possible to allocate an arbitrary number of instances from a
 type method on a singular pointer, but not from a buffer pointer. The 
result of such an operation returns a singular pointer, even though a 
buffer pointer would be more appropriate to capture the information 
about the <i>number</i> of instances allocated. It’s possible to subscript into a singular pointer, even though they are not real <code>Collection</code>s. Some parts of the current design turn UnsafePointers into downright <i>Dangerous</i>Pointers, leading users to believe that they have allocated or freed memory when in fact, they have not.</p><p>This proposal seeks to iron out these inconsistencies, and offer a 
more convenient, more sensible, and less bug-prone API for Swift 
pointers.</p><p>&lt;<a href="https://gist.github.com/kelvin13/a9c033193a28b1d4960a89b25fbffb06" target="_blank">https://gist.github.com/kelvi<wbr>n13/a9c033193a28b1d4960a89b25f<wbr>bffb06</a>&gt;</p><p>~~~<br></p></div></div></div></div></blockquote><br></div><div><div>Thanks for taking time to write this up.</div><div><br></div><div>General comments:</div><div><br></div><div>UnsafeBufferPointer is an API layer on top of UnsafePointer. The role</div><div>of UnsafeBufferPointer is direct memory access sans lifetime</div><div>management with Collection semantics. The role of UnsafePointer is</div><div>primarily C interop. Those C APIs should be wrapped in Swift APIs that</div><div>take UnsafeBufferPointer whenever the pointer represents a C array. I</div><div>suppose making UnsafePointer less convenient would push developers</div><div>toward UnsafeBufferPointer. I don&#39;t think that&#39;s worth outright</div><div>breaking source, but gradual deprecation of convenience methods, like</div><div>`susbscript` might be acceptable.</div></div></div></blockquote><br></div><div class="gmail_quote">Gradual deprecation is exactly what I am proposing. As the <a href="https://gist.github.com/kelvin13/a9c033193a28b1d4960a89b25fbffb06#proposed-solution" target="_blank">document states</a>, the only methods which should be marked immediately as unavailable are the `<span style="font-family:monospace,monospace">deallocate(capacity:)</span>` methods, for safety and source compatibility reasons. Removing `<span style="font-family:monospace,monospace">deallocate(capacity:)</span>` now and forcing a loud compiler error prevents catastrophic *silent* source breakage in the future, or worse, from having to *support our own bug*.<br></div><div class="gmail_quote"> <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div><br></div><div>I have mixed feelings about stripping UnsafePointer of basic</div><div>functionality. Besides breaking source, doing that would be</div><div>inconsistent with its role as a lower API layer. The advantage would</div><div>just be descreasing API surface area and forcing developers to use a</div><div>higher-level API.</div></div></div></blockquote><div><br></div><div>UnsafePointer is as much a high level API as UnsafeBufferPointer is.</div></div></div></div></div></blockquote><div><br></div></div></div><div>No it isn’t. We don’t have support for importing certain function signatures as taking UnsafeBufferPointer and UnsafePointer doesn&#39;t conform to Collection even though it nearly always represents an array.</div></div></div></blockquote><div><br></div><div>C functions get imported as taking UnsafePointers because buffer pointers in C are represented as pointer–length pairs. UnsafePointer can’t conform to Collection because there’s no way to automatically associate that length information with the pointer. So why do you think UnsafePointers should support doing Collection-y things if a precondition for performing collection-y operations is knowing the length? No sense exposing a `<span style="font-family:monospace,monospace">capacity</span>` argument if you don’t have a `<span style="font-family:monospace,monospace">count</span>` to go in it. That’s why I don’t really agree with viewing UnsafePointers as arrays, since trying to do random access into something you don’t know the length of seems off to me.<br> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> You wouldn’t create a buffer pointer of length 1 just so you can “stick with the high level API”. UnsafePointer and UnsafeBufferPointer are two tools that do related but different things and they can exist at whatever abstract level you need them at. After all, UnsafeBufferPointer is nothing but an UnsafePointer? with a length value attached to it. If you’re allocating more than one instance of memory, you almost certainly need to track the length of the buffer anyway.</div></div></div></div></div></blockquote><div><br></div></span><div><div>You could call this a proposal to &quot;make unsafe pointer APIs easier to use safely&quot;. I just want to put an end to the fallacy that the buffer type is for multiple values and the plain old pointer represents single instances.</div></div></div></div></blockquote><div><br></div><div>I mean, parts of the current API do heavily suggest that the plain pointer is for single instances — there’s the `<span style="font-family:monospace,monospace">pointee</span>` property after all. `<span style="font-family:monospace,monospace">move()</span>` vacates and returns a single element. In fact, I’m not sure when you would initialize multiple values, and then only vacate the one at offset 0. `<span style="font-family:monospace,monospace">successor()</span>` and `<span style="font-family:monospace,monospace">predecessor()</span>` only make sense if a pointer represents one single thing — it’d be weird if they represented some kind of weird sliding window where one end is `<span style="font-family:monospace,monospace">pointee</span>` and the other end is… ???.<br><br></div><div>My point being, you can only (safely) use the multiple-instance API if you have access to the count of elements. But if you have access to the count, <i>you effectively have a BufferPointer</i>. So why not put the buffer tools in the buffer shed?<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div>The additive changes you propose are fairly obvious. See [SR-3088]</div><div>UnsafeMutableBufferPointer doesn&#39;t have an allocating init.</div><div><br></div><div>I haven&#39;t wanted to waste review cycles on small additive</div><div>changes. It may make sense to batch them up into one coherent</div><div>proposal. Here are a few more to consider.</div><div><br></div><div>- [SR-3929] UnsafeBufferPointer should have init from mutable</div><div>- [SR-4340] UnsafeBufferPointer needs a withMemoryRebound method</div><div>- [SR-3087] No way to arbitrarily initialise an Array&#39;s storage</div></div></div></blockquote><div><br></div><div>The feature requests you mention are all very valuable, however with Michael’s point about fixing the memorystate API’s, the size of this proposal has already grown to encompass dozens of methods in five types. I think this says a lot about just how broken the current system is, but I think it’s better to try to fix one class of problems at a time, and save the less closely-related issues for separate proposals.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div><br></div><div>Point by point:</div><div><br></div><div>&gt; drop the capacity parameter from UnsafeMutablePointer.allocate(<wbr>) and deallocate().</div><div><br></div><div>I do not agree with removing the capacity parameter and adding a</div><div>single-instance allocation API. UnsafePointer was not designed for</div><div>single instances, it was primarily designed for C-style arrays. I</div><div>don&#39;t see the value in providing a different unsafe API for single</div><div>vs. multiple values.</div></div></div></blockquote><div><br></div><div>Although it’s common to *receive* Unsafe__Pointers from C API’s, it’s rare to *create* them from the Swift side. 95% of the time your Swift data lives in a Swift Array, and you use withUnsafePointer(_:) to send them to the C API, or just pass them directly with Array bridging. <br><br></div><div>The only example I can think of where I had to allocate memory from the Swift side to pass to a C API is when I was using the Cairo C library and I wanted the Swift code to own the image buffer backing the Cairo C structs and I wanted to manage the memory manually to prevent the buffer backing from getting deallocated prematurely. I think I ended up using UnsafeMutableBufferPointer and extracting baseAddresses to manage the memory. This proposal tries to mitigate that pain of extracting baseAddresses by giving buffer pointers their own memory management methods.<br></div></div></div></div></div></blockquote><div><br></div></span><div>The usability issue with Optional baseAddress is a very real one. I&#39;m unsure why that hasn&#39;t been fixed yet (I think that’s between Jordan and Dave). I don&#39;t see that as a justification for the broader changes in this proposal.</div></div></div></blockquote><div><br></div><div>This was actually part of the <a href="https://gist.github.com/kelvin13/a9c033193a28b1d4960a89b25fbffb06/cc3d7c349e5f5600ae592ee394438f68068df15b">first drafts</a> of the proposal. I was told this had already been discussed at length, and the community supposedly decided against it a long time ago, so it was removed from the proposal.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><div><br></div><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>As for the UnsafePointers you get from C APIs, they almost always come with a size (or you specify it beforehand with a parameter) so you’re probably going to be turning them into UnsafeBufferPointers anyway.<br><br></div><div>I also have to say it’s not common to deallocate something in Swift that you didn’t previously allocate in Swift. <br></div></div></div></div></div></blockquote><div><br></div></span><div>Yes. You have a good argument for removing allocate/deallocate completely. My point was that I don&#39;t want to add a single instance allocate method. UnsafePointer should not be viewed as a single instance pointer, because that&#39;s not how it&#39;s used.</div><span class="gmail-"><div><br></div></span></div></div></blockquote><div><br></div><div>So, should `<span style="font-family:monospace,monospace">UnsafeMutableBufferPointer&lt;Element&gt;.allocate(count: 1).baseAddress!</span>` be the preferred way to allocate a single instance? Or `<span style="font-family:monospace,monospace">UnsafeMutablePointer&lt;T&gt;.allocate(count: 1)</span>` if we keep 2 sets of APIs? Writing “<span style="font-family:monospace,monospace">count: 1</span>” seems kind of strange to me.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><div></div><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div>I agree the primary allocation API should be</div><div>UnsafeMutableBufferPointer.all<wbr>ocate(capacity:). There is an argument</div><div>to be made for removing UnsafeMutablePointer.allocate(<wbr>capacity:)</div><div>entirely. But, as Michael Ilseman pointed out, that would involve</div><div>reevaluating several other members of the UnsafePointer API. I think</div><div>it&#39;s reasonable for UnsafePointer to retain all its functionality as a</div><div>lower level API.</div><div><br></div></div></div></blockquote><div><br></div><div>I think duplication of functionality is something to be avoided if possible.<br></div></div></div></div></div></blockquote><div><br></div></span><div>The issue is whether we need to revisit all the initialize/deinitialize/move API surface if we decide that all the uses that can me moved to UnsafeBufferPointer really should be.</div></div></div></blockquote><div><br></div><div>I was working that out earlier today. The <a href="https://gist.github.com/kelvin13/a9c033193a28b1d4960a89b25fbffb06">latest version</a> outlines exactly what I think should happen to all the memorystate functions.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><div> </div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div></div><div>I don&#39;t understand what is misleading about</div><div>UnsafePointer.deallocate(capac<wbr>ity:). It *is* inconvenienent for the</div><div>user to keep track of memory capacity. Presumably that was done so</div><div>either the implementation can move away from malloc/free or some sort</div><div>of memory tracking can be implemented on the standard library</div><div>side. Obviously, UnsafeBufferPointer.deallocate<wbr>() would be cleaner in</div><div>most cases.</div></div></div></blockquote><div><br></div><div>It’s misleading because it plain doesn’t deallocate `capacity` instances. It deletes the whole memory block regardless of what you pass in the capacity argument. If the implementation is ever “fixed” so that it actually deallocates `capacity` instances, suddenly every source that uses `deallocate(capacity:)` will break, and *no one will know* until their app starts mysteriously crashing. If the method is not removed, we will have to support this behavior to avoid breaking sources, and basically say “yes the argument label says it deallocates a capacity, but what it *really* does is free the whole block and we can’t fix it because existing code assumes this behavior”.<br></div></div></div></div></blockquote><div><br></div></span><div>You could have the same problem with slicing up an UnsafeBufferPointer. I agree that this reinforces the argument for eliminating UnsafeMutablePointer.allocate/<wbr>deallocate. It also reinforces my argument for not adding a single-instance allocate/deallocate.</div><span class="gmail-"><div><br></div></span></div></div></blockquote><div><br></div><div>You have a good point here, it’s still not very safe, but I hold that it is still far, far safer than what we have currently. Getting rid of the `capacity` label helps drive home that swift_slowDealloc doesn’t care what number of instances you want it to free. Unsafe__Pointers will always be unsafe, but if we can make them less unsafe, we should.<br><br></div><div>I’ll admit this is a good argument against “single instance” <span style="font-family:monospace,monospace">deallocate</span>. We don’t want people trying to free each address in a buffer pointer 😨. But it’s not a direct argument against single instance allocate, which I think would be very useful, and it would be weird to have single instance <span style="font-family:monospace,monospace">allocate</span> but no corresponding <span style="font-family:monospace,monospace">deallocate</span>. We also have to consider what happens to the proposed single-instance memorystate functions, as those *are* safe and *are* useful. Should single-instance <span style="font-family:monospace,monospace">deallocate</span> be the one missing function? I agree this is definitely something to think carefully about.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><span class="gmail-"><div></div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div>&gt; add an allocate(count:) type method to UnsafeMutableBufferPointer</div><div><br></div><div>`capacity` should be used for allocating uninitialized memory not</div><div>`count`. `count` should only refer to a number of initialized objects!</div></div></div></blockquote><div><br></div><div>We can decide on what the correct term should be, but the current state of Swift pointers is that *neither* convention is being followed. Just look at the API for UnsafeMutableRawPointer. It’s a mess. This proposal at the minimum establishes a consistent convention. It can be revised if you feel `capacity` is more appropriate than `count`. If what you mean is that it’s important to maintain the distinction between “initialized counts” and “uninitialized counts”, well that can be revised in too.</div></div></div></div></blockquote><div><br></div></span><div>You lost me. It’s always been clear to me that</div><div><br></div><div>a. There are a lot of redundant initializers to avoid relying on automatic conversion. Those should probably be removed now (to the extent that it doesn’t break source).</div><div><br></div><div>b. There are a number of convenience methods we should add to the API. But it’s better keep the API minimal until more developers, such as yourself, have had a chance to offer feedback.</div><div><br></div><div>I’m not aware of messiness or inconsistent conventions at the API level.</div><div><br></div>-Andy</div><span class="gmail-"><div><br></div></span></div></blockquote><div><br></div><div>I’m confused I thought we were talking about the naming choices for the argument labels in those functions. I think defining and abiding by consistent meanings for `<span style="font-family:monospace,monospace">count</span>`, `<span style="font-family:monospace,monospace">capacity</span>`, and `<span style="font-family:monospace,monospace">bytes</span>` is a good idea, and it’s part of what this proposal tries to accomplish. Right now half the time we use `count` to refer to “bytes” and half the time we use it to refer to “instances”. The same goes for the word “capacity”. This is all laid out in the document:<br><br>“““<br><em>Finally, the naming and design of some <code>UnsafeMutableRawPointer</code> members deserves to be looked at. The usage of <code>capacity</code>, <code>bytes</code>, and <code>count</code> as argument labels is wildly inconsistent and confusing. In <code>copyBytes(from:count:)</code>, <code>count</code> refers to the number of bytes, while in <code>initializeMemory&lt;T&gt;(as:at:count:to:)</code> and <code>initializeMemory&lt;T&gt;(as:from:count:)</code>, <code>count</code> refers to the number of strides. Meanwhile <code>bindMemory&lt;T&gt;(to:capacity:)</code> uses <code>capacity</code> to refer to this quantity. The always-problematic <code>deallocate(bytes:alignedTo)</code> method and <code>allocate(bytes:alignedTo:)</code> type methods use <code>bytes</code> to refer to byte-quantities. Adding to the confusion, <code>UnsafeMutableRawBufferPointer</code> offers an <code>allocate(count:)</code> type method (the same signature method we’re trying to add to <code>UnsafeMutableBufferPointer</code>), except the <code>count</code> in this method refers to bytes. This kind of API naming begets stride bugs and makes Swift needlessly difficult to learn.</em><br>”””<br><br></div><div>The only convenience methods this proposal is trying to add is the functionality on the buffer pointer types. There seems to be broad support for adding this functionality as no one has really opposed that part of the proposal yet. Any other new methods like `<span style="font-family:monospace,monospace">UnsafeMutablePointer.assign(to:)</span>` are there for API consistency.<br><br></div><div>This proposal also calls for getting rid of one of those “redundant initializers” :)<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><span class="gmail-"><div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div></div></div></div></blockquote><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div>&gt; add a deallocate() instance method to UnsafeMutableBufferPointer</div><div><br></div><div>Yes, of course! I added a mention of that in SR-3088.</div><div><br></div><div>&gt; remove subscripts from UnsafePointer and UnsafeMutablePointer</div><div><br></div><div>It&#39;s often more clear to perform arithmetic on C array indices rather</div><div>than pointers. That said, I&#39;m happy to push developers to use</div><div>UnsafeBufferPointer whenever that have a known capacity. To me, this</div><div>is a question of whether the benefit of making a dangerous thing less</div><div>convenient is worth breaking source compatibility.</div></div></div></blockquote><div><br></div><div>Again, I think this is more about what the real use patterns are. If you are subscripting into a C array with integers, then UnsafeBufferPointer is the tool for the job, since it give you Collection conformance. If you can’t make an UnsafeBufferPointer, it’s probably because you don’t know the length of the array, and so you’re probably iterating through it one element at a time. UnsafeMutablePointer.<wbr>successor() is perfect for this job. If you want to extract or set fields at fixed but irregular offsets, UnsafeRawPointer is the tool for the job. But I’m hard-pressed to think of a use case for random access into a singular typed pointer.<br></div></div><br></div></div>
</blockquote></div><br></span></div></blockquote></div><br></div><div class="gmail_extra">Thanks for your feedback on my proposal. You’ve given some very helpful considerations about some of these changes.<br></div></div>