We discussed this a bit in the language workgroup and mentioned it in some offline conversations, but I wanted to make sure our thoughts/concerns made it into this thread as well.
There are two main reasons that folks forward declare a class/protocol:
- To break a cyclic dependency between two types.
- To improve build performance by not requiring the compiler to parse headers when the type's name provides enough information for a particular usage.
Regarding #1, Swift by design does not permit circular dependencies between Swift types in different modules; for two types to depend on each other, they must be in the same module. If we resolve forward declarations of the form @class/@protocol
to matching Objective-C-compatible Swift types, then this opens a "back door" to get around that limitation—a user could use an intermediary Objective-C module to create a cyclic relationship between two Swift types. This could make it harder to reason about those types when compiling Swift code that uses them.
For #2, the generated header is again a compiler artifact by design, and it contains various metadata about the declaration beyond just what a forward-declaration contains. For example, by marking the generated @interface
with information about its originating module, IDE actions like "jump-to-definition" can find the original type definition in Swift instead of just pointing to a forward declaration that's otherwise divorced from all context. The implementation work needed to get around this limitation, and potentially other related issues, are unnecessary if we just tell users of classes implemented in Swift to "just import the generated header".
My general feeling is that if someone does want to have a class that's implemented in Swift but is indistinguishable from an Objective-C class, including full header control and the ability to forward declare it, then other recently-pitched features like @objcImplementation
are likely to be a better fit.