<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 Feb 14, 2017, at 7:18 AM, Charles Srstka 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=""><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="">MOTIVATION:<div class=""><br class=""></div><div class="">In Swift 3, NSFileHandle was renamed to FileHandle, making it the de facto file handle class for use in Swift applications. Unfortunately, it’s not a very good API. NSFileHandle supports no error reporting whatsoever, instead throwing Objective-C exceptions whenever something goes wrong during reading or writing. There is no way that I know of to catch these exceptions in Swift, meaning that if a write failed because the disk ran out of space or something, there’s no way to deal with that other than crashing the whole application.</div><div class=""><br class=""></div><div class="">In addition, NSFileHandle’s asynchronous API is broken. It provides a readabilityHandler property which allows blocks-based reading of files, but this handler does not provide any way to detect when the end of the file is reached, which makes it not useful for many applications.</div></div></div></blockquote><div><br class=""></div><div>For what it's worth, the readability handler is intended to be an analogue to select, kevent, or DISPATCH_SOURCE_TYPE_READ, not an async reading mechanism itself. Using real async IO like readInBackground* will be more efficient, and get you the EOF handling you expect. It's somewhat unfortunate that this relatively specialized API ended up looking so much more appealing than the more generally useful one, and that's something that could be improved in the future.</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>David </div><br class=""><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=""><br class=""></div><div class="">PROPOSED SOLUTION:</div><div class=""><br class=""></div><div class="">Rename FileHandle back to NSFileHandle, and provide a Swift-native FileHandle class for Foundation in Swift 4 that mimics NSFileHandle’s interface, but provides throwing versions of all the read and write methods:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">open</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">class</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> FileHandle : </span><span style="font-variant-ligatures: no-common-ligatures" class="">NSObject</span><span style="font-variant-ligatures: no-common-ligatures;" class="">, </span><span style="font-variant-ligatures: no-common-ligatures" class="">NSSecureCoding</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);" class="">open</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);" class="">func</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> readDataToEndOfFile() <span style="color: rgb(186, 45, 162);" class="">throws</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> -> </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Data</span></span><span style="font-variant-ligatures: no-common-ligatures" class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">open</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> readData(ofLength length: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Int</span><span style="font-variant-ligatures: no-common-ligatures" class="">) </span><span style="color: rgb(186, 45, 162);" class="">throws </span><span style="font-variant-ligatures: no-common-ligatures;" class="">-> </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Data</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">open</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> write(</span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> data: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Data</span><span style="font-variant-ligatures: no-common-ligatures" class="">) </span><span style="color: rgb(186, 45, 162);" class="">throws</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="color: rgb(186, 45, 162);" class=""><br class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> // etc.</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class="">Much of the work for this is already done, in the swift-corelibs-Foundation project. The main thing that would need to be done for the synchronous APIs would be simply to replace the fatalErrors with throws, a simple enough operation. The asynchronous read/write APIs are still unimplemented in corelibs, but given that a new implementation of those based on DispatchIO could be engineered in such a way that it would correctly report EOF, the benefits to the end-user would likely justify the expense.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">For backward source compatibility, the existing, non-throwing APIs could be provided as well, but deprecated. These could simply call the throwing APIs and either call fatalError() or throw an NSException when an error is caught.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Since FileHandle is just a wrapper around a file descriptor, bridging to Objective-C should not be difficult; just use the file descriptor from one side to build a handle on the other side.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">IMPACT ON EXISTING CODE:</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Since the new class would have the same name as the existing FileHandle class, as it is exposed to Swift, this would not break source compatibility. It would break binary compatibility, which makes it a consideration for Swift 4.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Charles</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>