Property wrapper for automatically closing file descriptors

Since FileDescriptor is not automatically closed on deinit, I would like to propose adding a property wrapper that automatically closes the wrapped file descriptor.

Here is my first draft:

public protocol Cloesable {
    func close() throws
}

extension Optional: Cloesable where Wrapped: Cloesable {
    public func close() throws {
        try self?.close()
    }
}

/// Automatically closes the wrapped file descriptor on deinit.
@propertyWrapper public final class AutoClosing<Descriptor: Cloesable> {
    public var wrappedValue: Descriptor

    public init(wrappedValue: Descriptor) {
        self.wrappedValue = wrappedValue
    }

    deinit {
        try? wrappedValue.close()
    }
}

try? wrappedValue.close() is obviously not ideal here.

Maybe we can add something like FileHandle?

1 Like

Long term, I think we want a move-only File type that will close on release and encapsulate the file descriptor.

4 Likes

I think this is the key problem with this pattern in general. At the level of abstraction on which System's APIs operate, neither silently ignoring the error nor crashing feels like an appropriate choice. System ought to faithfully reflect the low-level C system APIs that it is adapting, and I suspect that in most cases that includes manual management of resources. (Resources other than memory, that is.)

There is a similar issue with FileDescriptor.closeAfter -- when both the closure and close throw, only the closure's error gets propagated outside. This makes this function less useful: if I need to, say, log the error instead, I'll need to roll my own version of it, or just write the equivalent code inline.

But closeAfter is just a simple convenience method -- it was extremely cheap to add, and it draws minimal attention in the module's API surface. System would be just as powerful without this function, but its addition slightly improved usability for a common case at essentially zero cost.

Adding a protocol plus a number of conformances plus a property wrapper class(!) for a convenience feature that has similar scope except with an even more serious flaw seems like a far more difficult sell to me. That said, it may be worth revisiting this once this package covers more system functionality -- a protocol like this may make more sense for something like a pthread mutex, where errors during disposal usually indicate a programming error.