<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 Jul 17, 2017, at 10:06 PM, Taylor Swift via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">I’ve drafted a new version of the unsafe pointer proposal based on feedback I’ve gotten from this thread. You can read it <a href="https://gist.github.com/kelvin13/1b8ae906be23dff22f7a7c4767f0c907" class="">here</a>.<br class=""><br class="">~~~<br class=""><p class="">Swift’s pointer types are an important interface for low-level memory
manipulation, but the current API design is not very safe, consistent,
or convenient. Many memory methods demand a <code class="">capacity:</code> or <code class="">count:</code>
argument, forcing the user to manually track the size of the memory
block, even though most of the time this is either unnecessary, or
redundant as buffer pointers track this information natively. In some
places, this design turns UnsafePointers into outright <em class="">Dangerous</em>Pointers, leading users to believe that they have allocated or freed memory when in fact, they have not.</p><p class="">The current API suffers from inconsistent naming, poor usage of
default argument values, missing methods, and excessive verbosity, and
encourages excessively unsafe programming practices. 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 class="">The <a href="https://gist.github.com/kelvin13/a9c033193a28b1d4960a89b25fbffb06" class="">previous draft</a>
of this proposal was relatively source-breaking, calling for a
separation of functionality between singular pointer types and vector
(buffer) pointer types. This proposal instead separates functionality
between internally-tracked length pointer types and externally-tracked
length pointer types. This results in an equally elegant API with about one-third less surface area.</p><p class=""><<a href="https://gist.github.com/kelvin13/1b8ae906be23dff22f7a7c4767f0c907" class="">https://gist.github.com/kelvin13/1b8ae906be23dff22f7a7c4767f0c907</a>><br class=""></p><p class="">~~~<br class=""></p></div></div></blockquote></div><div class="">> remove the capacity parameter from deallocate(capacity:) and deallocate(bytes:alignedTo:)</div><div class=""><br class=""></div><div class="">That's probably for the best.</div><div class=""><br class=""></div><div class="">> add unsized memory methods to UnsafeMutableBufferPointer</div><div class=""><br class=""></div><div class="">Yay!</div><div class=""><br class=""></div><div class="">> add an assign(to:count:) method to UnsafeMutablePointer and an assign(to:) method to UnsafeMutableBufferPointer</div><div class=""><br class=""></div><div class="">Sure.</div><div class=""><br class=""></div><div class="">> add a default value of 1 to all size parameters on UnsafeMutablePointer and applicable</div><div class="">> size parameters on UnsafeMutableRawPointer</div><div class=""><br class=""></div><div class="">I'm not opposed to it.</div><div class=""><br class=""></div><div class="">> rename copyBytes(from:count:) to copy(from:bytes:)</div><div class=""><br class=""></div><div class="">LGTM in the interest of consistency. I should not have caved on this the first time around.</div><div class=""><br class=""></div><div class="">> bytes refers to, well, a byte quantity that is not assumed to be initialized.</div><div class="">> capacity refers to a strided quantity that is not assumed to be initialized.</div><div class="">> count refers to a strided quantity that is assumed to be initialized.</div><div class=""><br class=""></div><div class="">That's how I see it.</div><div class=""><br class=""></div><div class="">> rename count in UnsafeMutableRawBufferPointer.allocate(count:) to bytes and add an</div><div class="">> alignedTo parameter to make it UnsafeMutableRawBufferPointer.allocate(bytes:alignedTo:)</div><div class=""><br class=""></div><div class="">Memory allocation is an issue unto itself. I generally prefer your</div><div class="">proposed API. However...</div><div class=""><br class=""></div><div class="">1. Larger-than-pointer alignments aren't currently respected.</div><div class=""><br class=""></div><div class="">2. Users virtually never want to specify the alignment explicitly. They</div><div class=""> just want platform alignment. Unfortunately, there's no reasonable</div><div class=""> "maximal" alignment to use as a default. I think pointer-alignment</div><div class=""> is an excellent default guarantee.</div><div class=""><br class=""></div><div class="">3. The current allocation builtins seem to presume that</div><div class=""> allocation/deallocation can be made more efficient if the user code</div><div class=""> specifies alignment at deallocation. I don't think</div><div class=""> UnsafeRawBufferPointer should expose that to the user, so I agree</div><div class=""> with your proposal. In fact, I think aligned `free` should be</div><div class=""> handled within the Swift runtime.</div><div class=""><br class=""></div><div class="">Resolving these issues requires changes to the Swift runtime API and</div><div class="">implementation. This might be a good time to revisit that design, but</div><div class="">it might slow down the rest of the proposal.</div><div class=""><br class=""></div><div class="">> fix the ordering of the arguments in initializeMemory<Element>(as:at:count:to:)</div><div class=""><br class=""></div><div class="">I think this ordering was an attempt to avoid confusion with binding</div><div class="">memory where `to` refers to a type. However, it should be consistent</div><div class="">with `UnsafePointer.initialize`, so we need to pick one of those to</div><div class="">change.</div><div class=""><br class=""></div><div class="">> add the sized memorystate functions withMemoryRebound<Element, Result>(to:count:_:) to</div><div class="">> UnsafeMutableBufferPointer, and initializeMemory<Element>(as:at:to:count:),</div><div class="">> initializeMemory<Element>(as:from:count:) moveInitializeMemory<Element>(as:from:count:),</div><div class="">> and bindMemory<Element>(to:count:) to UnsafeMutableRawBufferPointer</div><div class=""><br class=""></div><div class="">Yay!</div><div class=""><br class=""></div><div class="">> add mutable overloads to non-vacating memorystate method arguments</div><div class=""><br class=""></div><div class="">I'm not sure removing the need for implicit casts is a goal. I did</div><div class="">that with the pointer `init` methods, but now I think that should be</div><div class="">cleaned up to reduce API surface. I think smaller API surface wins in</div><div class="">these cases. Is there a usability issue you're solving?</div><div class=""><br class=""></div><div class="">> add a init(mutating:) initializer to UnsafeMutableBufferPointer</div><div class=""><br class=""></div><div class="">Yes, finally.</div><div class=""><br class=""></div><div class="">> remove initialize<C>(from:) from UnsafeMutablePointer</div><div class=""><br class=""></div><div class="">Yep.</div><div class=""><br class=""></div><div class="">> adding an initializer UnsafeMutableBufferPointer<Element>.init(allocatingCount:) instead > of a type method to UnsafeMutableBufferPointer</div><div class=""><br class=""></div><div class="">For the record, I strongly prefer a type method for allocation for the reason you mention, it has important side effects beyond simply initializingn the pointer.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">-Andy</div></body></html>