This is a great question! To answer it thoroughly we need to take a digression into the Swift optimiser and optimisation boundaries, but the TL;DR is that @usableFromInline
is required to make substantial chunks of NIO perform better.
The more detailed answer here is that methods (including property accessors) in Swift can be marked as @inlinable
. The effect of doing this is that it makes the implementation of the method part of the public interface of the module. In modules that export a stable ABI this is a substantial commitment, as it is no longer the method itself that is part of the ABI, but it is the entire body of the method. Anything relied on by the body of the method cannot be changed without breaking the ABI.
To help drive this home, Swift requires that anything touched by an @inlinable
method must meet one of the following requirements:
- Be
public
; OR - Be
@inlinable internal
; OR - Be
@usableFromInline internal
The intent of this is to make it clear that any such declaration is part of the public ABI and cannot safely be changed.
Note that neither @inlinable
or @usableFromInline
can be applied to a private
or fileprivate
declaration. There are some complex reasons for why to do with symbol name clashes that are largely not worth getting into here (basically, things that are @usableFromInline
must be unique in the module, which clashes with the expected behaviour of private
/fileprivate
). As a result, NIO is forced to choose: its preferred symbol visibility, or the ability to be used in an inlinable method.
So why do we care about @inlinable
?
The answer is that Swift cannot optimise code across module boundaries. This includes generic specialization, but it also includes optimisations around refcounts and ownership and a number of other things. For this reason, we pay careful attention to places where inlinable declarations make sense. This is particularly common in our core data structures.