Introduction
Cross import overlays are incredible. Truly, they’re a gamechanger. It’s a feature that allows Swift to automatically import an additional “overlay” module basd on the combination of imports in a particular source file. They let a library or framework seamleslly expand (or rely) upon another, without imposing an additonal dependency on clients who don’t need it.
Let’s say you’re developing an open source library, let’s call it ModelKit
. Let’s also say that this library could be enhanced by a third party open source library (let’s call it, CoolKit
). There are several ways to pull this off:
- You can create a second library, called
CoolModelKit
. This library importsCoolKit
and uses it to enhance the models ofModelKit
. - You can import
CoolKit
directly intoModelKit
, but this will likely upset consumers ofModelKit
that don’t need or wantCoolKit
in their projects. - You can create a cross import overlay, that automatically adds in the
CoolKit
enhancements to your library when both are imported in a single file.
How Cross Import Overlays Work
Cross import overlays are declared by special YAML files that specify which modules should be imported together and what overlay module should be added as a result. That means that we do need a third module, that by naming convention is called _ModelKit_CoolKit
(it belongs to ModelKit
, and pulls in CoolKit
to extend it). Let’s create a module called _ModelKit_CoolKit
where we have our extensions of ModelKit
.
In these files, when we import ModelKit
, we are actually declaring @_exported import ModelKit
. Effectively, what the compiler will do is look for the following in consumer code:
import ModelKit
import CoolKit
and replace it with:
import _ModelKit_CoolKit
import CoolKit
In order to pull this off, you need a .swiftoverlay
file inside of a .swiftcrossimport
folder. Let’s take a look a For example, the NumericKitFormatKitAdditions overlay module could be declared by a file named NumericKit_FormatKit.overlay.yaml with the following content:
%YAML 1.2
---
version: 1
modules:
- name: _ ModelKit_CoolKit
This file tells Swift that whenever both ModelKit
and CoolKit
are imported in the same source file, it should make the replacement. The overlay module itself is a regular Swift module that can define extensions, conformances, types, functions, etc. that depends on both ModelKit
and CoolKit
.
The YAML files are located in special directories inside the frameworks or libraries that declare them. For example,
- For an Apple framework named
Foo.framework
, they are located underFoo.framework/Modules/Foo.swiftcrossimport/
. - For a third-party framework named
Bar.framework
, they are located underBar.framework/Resources/SwiftCrossImport/
. - For a library named
Baz.a
, they are located underBaz.swiftcrossimport/
. Swift scans these directories at compile time and loads the YAML files as needed. The YAML files can also specify conditions for when the overlay module should be imported based on platform availability or compiler flags.
How to use them today
Unless you are using Xcodegen
, you’ll have to manually place these yaml files inside of the output frameworks/libraries. If you are using XcodeGen
, I’ve merged support.
All you’ll have to do is have your MyModule.crossimport
folder with a _MyModule_Extensions.swiftoverlay
file in your target’s Sources
, and a declared _MyModule_Extensons
target somewhere.
Benefits of Cross Import Overlays
Cross import overlays offer several benefits for library authors and users:
- They enable seamless interoperability between libraries without requiring explicit imports or extra dependencies.
- They allow library authors to modularize their code and avoid bloating their main modules with functionality that only some users need.
- They encourage library authors to provide consistent and idiomatic APIs for common use cases involving multiple libraries.
- They reduce compile time and link time overhead by avoiding unnecessary imports of unused modules.
- They avoid retroactive conformances that can cause problems with library evolution.
Downsides of Cross Import Overlays
- They’re not supported in SPM yet.
- They’re only supported via Xcodegen or manual setup.
- The compiler cannot automatically link required libraries together, unless that library is a system library. Crucially, this is what makes Apple’s usage of this feature function. If you are using
ModelKit
andCoolKit
inMyApp
, you’ll need to make sure thatMyApp
depends onModelKit
,CoolKit
, and_ModelKit_CoolKit
— even though you’ll never writeimport _ModelKit_CoolKit
in your application code.
Examples of Cross Import Overlays
Cross import overlays are already used by some Apple frameworks to provide better integration with other frameworks. For example:
- The
SwiftUI
framework uses cross import overlays to provide custom views and modifiers forMapKit
,AVFoundation
,SpriteKit
,SceneKit
,CoreImage
,Vision
,CoreData
,Combine
,PencilKit
,UniformTypeIdentifiers
,AppClipCodeGenerator
,LinkPresentation
, and more. - The
Combine
framework uses cross import overlays to provide extensions and operators forFoundation
(includingURLSession
),Dispatch
(includingDispatchQueue
),os
(includingOSLog
),CoreData
(includingNSManagedObjectContext
), etc. - The Swift standard library uses cross import overlays to provide additional functionality for
Darwin
(includingDarwinBoolean
),Glibc
(includinggnu_boolean
) andWindows
(includingBOOL
).
Conclusion
Cross import overlays are a powerful feature that enable Swift libraries to provide better interoperability and modularity. They allow library authors to define additional modules that are automatically imported when two or more modules are used together, without requiring explicit imports or extra dependencies from the users. They also reduce compile time and link time overhead and avoid retroactive conformances. Cross import overlays are already used by some Apple frameworks to provide custom views and modifiers for SwiftUI , extensions and operators for Combine , and more.
There’s not much out there as far as detail on this feature, but if this is something you’re interested in, please reach out to me on Mastodon for more information and give the proposal which details them a read.