After the long discussion on the previous thread, @John_McCall and I went away to go prototype the main new feature: implementation-only imports. (I'm staying away from "private imports" to avoid the implications of access control for now, as well as the other experimental "private imports" feature that's in support of dynamic method replacement.) We've been doing this work on the master and 5.1 branches of the compiler so that some Apple projects can live on it for a while to make sure (1) it works, and (2) the design is actually what we want. Note that it's not going to be an official feature of Swift 5.1.
Meanwhile, if you want to play around with it, a reminder that this is unsupported, possibly buggy, and definitely not the final syntax. But other than that, you're welcome to!
Right now the new feature looks like this:
// MyKit.swift
@_implementationOnly import SecretKit
The name is pretty unwieldy right now since we expect that'll be a hot topic of discussion. (We've gotten some feedback that it'd be worth trying to change the default semantics of import
; I'm personally skeptical whether we can do this in a non-breaking way.)
What does this do today?
-
Clients of MyKit will not need SecretKit around when using MyKit. SecretKit won't even be loaded, avoiding the problems listed in "@_exported and fixing import visibility".
-
The public API and ABI of MyKit is not allowed to use any declarations from SecretKit. This is enforced by the compiler.
-
The public API and ABI of MyKit is not allowed to rely on conformances declared in SecretKit, even if the types involved are from other modules. This is subtle but probably won't come up in practice. (Also enforced by the compiler.)
-
The public types of MyKit are not allowed to conform to protocols in SecretKit. We consider this a limitation, but it's a tricky restriction to lift given the way the several parts of the compiler work right now.
-
If a public type in MyKit overrides a method defined in SecretKit, the override has to be marked
@_implementationOnly
as well, so that it can be omitted from the module interface. This feels quite hacky to me; everywhere else things are enforced by the compiler, but here the compiler mostly just trusts the developer to get it right once they've put the attribute on. -
A generated module interface (.swiftinterface file) will not make any mention of SecretKit, and should not reference anything from SecretKit either.
-
The compiled module (.swiftmodule file) may still have references to SecretKit for debugging and testing purposes. This means that the compiler must know not to rely on the parts that depend on SecretKit when the compiled module is used for building clients. (This is where 90% of the known issues are right now.)
-
@testable import MyKit
is probably completely broken. This should probably bring in the implementation-only dependencies of MyKit even though they normally wouldn't be brought in, since the alternative is to figure out what's being used in MyKit's internal types as well. -
LLDB support is only verrrry lightly tested. (I haven't even managed to land the PR with the tests in it, mostly because I've been busy with other things.)
-
I've tried not to make anything dependent on
-enable-library-evolution
, because I know people want this for packages, but the adopters within Apple are all using library evolution support, so it wouldn't surprise me if things are worse in "normal" / "fragile" mode.
Again, this is what's currently implemented, not necessarily what we want to propose in the long run. And it doesn't cover a number of other use cases, particularly vending content that's only present if the client asks for it.