Building on this: I gave some private feedback to the authors early in the proposal's development, and my first reaction was squarely in the "Why Don't We Just™ use @_spi
for this?" camp. Specifically, I asked them something like this:
Consider this alternative design:
- We turn
@_spi(...)
into a supported feature with some sensible name.- We introduce some kind of
-default-spi-group <default-group-name>
flag and have SwiftPM pass in the package name for it.- We treat
@_spi
with no group name as@_spi(<default-group-name>)
.- We add an implicit
@_spi(<default-group-name>)
to everyimport
, suppressing warnings for modules that don't have any SPI with that name.This alternative would cover more use cases. Why should we use your design instead?
And to be honest, I really thought that question would send them back to the drawing board. Instead, the authors successfully defended their design and convinced me that a new feature was the right solution.
They had a few good arguments, but the most important one was the library evolution differences. An important aspect of @_spi
's design is that in a resilient library, SPI declarations have exactly the same ABI as public declarations; this allows you to build clients separately and mix-and-match library and client versions, and it also allows you to retroactively publish SPI from toasterOS 9 as API in the toasterOS 10 SDK. But adopting the behavior of public declarations places certain limitations on them, and it forces clients to generate slower "resilient" code that allows the library implementation to change.
We've long known that forcing all clients of ABI-stable libraries to generate resilient code was not ideal, and from the beginning we've discussed the notion of a "resilience domain", a set of modules which could access each other's guts non-resiliently, but which were therefore version-locked to one another and would have to be upgraded or downgraded as a unit. But this was always a theoretical concept, discussed in five-plus years of design documents but never surfaced as an actual language feature.
SE-0386 finally gives us a path to making this hypothetical feature into something you can actually use—and with such nice ergonomics that it can simply be the default in SwiftPM packages, and probably in other build systems as well. And, as a nice bonus, we also get a useful new access level.
To me, that seems like a powerful motivation to build something distinct from @_spi
. It's not that @_spi
is bad or that we shouldn't formalize it eventually—it's just that we can get much more by building a different feature to address this specific use case.
I am very sympathetic to this issue and I think we might not want to tie the keyword quite so closely to the concept of a "package", but other than a half-joking suggestion of friend
, I don't have a great alternative to offer. Something based on team
is probably better than package
, but it's still a little misleading, since it makes perfect sense for a single engineering team to own several different "frogs". I'd prefer a word that says something about the modules, not the organization.