[Pre-Pitch] Import access control: a modest proposal

I like the public/internal distinction and agree that internal should be (or should have been) the default.

But it's been painful to watch the Java ecosystem struggle to migrate to the privacy of modules. One unmigrated library can foul many dependency trees.

In Swift, even applications may (should?) be composed of multiple modules, and need migrating. Applications targeting multiple OS platforms and versions might delay upgrading to a new language default of internal until all target platforms support it (a big lift if concurrency is not available on older platforms). This in turn stalls apps on old versions of libraries whose next version requires internal support. (Many Java libraries cite their clients when balking at converting to modules.)

I also like jordan rose on @_exported. Could this belong in package-level visibility control, where module/library publishers opt-in to internal?

E.g., let's say library L-1 in Package.swift can declare a dependency on a module L-0 to be internal, resulting in compiler errors when any L-0 types/names are used in the public API/ABI of L-1. That way, each library can opt in (or not) to using internal with their next version, and library clients manage around it at the same time they manage library version upgrades (i.e., they can remain on old versions if needed). And the new library itself can be used in older versions of Swift.

The scope change from per-import to per-module-dependency avoids the incongruity of multiple imports with different access levels and avoids the need for new access modifier on the import statement. But the cost is complexity: the full public API/ABI of module L-0 is visible to clients of L-1.

But that might be right. I'm a little uncomfortable with library/module L-1 selectively exposing types from module L-0 to application clients. That would mean there is a different view of L-0 for each L-n publishing L-0 types to app A (or for each import statement?). If the publisher of L-0 presents the only/fixed view of L-0, it might help incremental compilation and developer reasoning (at the cost of a larger API/ABI surface).

I'm not sure if this helps or hurts de-conflicting multiple internal dependencies on (different versions of) L-0. I'm prefer that happen early at package-declaration phase, rather than at link-time via discovery.

2 Likes