MOTIVATION:

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.

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.

PROPOSED SOLUTION:

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:

open class FileHandle : NSObject, NSSecureCoding {
    open func readDataToEndOfFile() throws -> Data

    open func readData(ofLength length: Int) throws -> Data

    open func write(_ data: Data) throws

    // etc.
}

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.

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.

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.

IMPACT ON EXISTING CODE:

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.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to