In an async runtime, there are some preparation steps that need to be done on the file descriptors, in order to use them.
They could be pipes, or could be backed by real files. These two cases require different strategies when using kqueue/epoll. Plus, if it's a pipe, it needs to be marked as non-blocking.
It would be ideal, if these were part of the vtable. It would also allow mock implementations of Io to provide their own.