[swift-evolution] 100% bikeshed topic: DictionaryLiteral

Chris Lattner clattner at nondot.org
Sat Jan 13 01:23:23 CST 2018

On Jan 12, 2018, at 4:43 PM, Ted Kremenek <kremenek at apple.com> wrote:
> Hi Chris,
> Instead of responding to each of your point bit-by-bit, I’ll try a different tactic to explain my reasoning — which may be wrong — by explaining how I see things top down with the tradeoffs they incur.  I’m going to say a bunch of things I know *you* know, but others are on this thread and I’ll state things for end-to-end clarity.

Sounds good.

> It seems to me that we are talking about two possible scenarios: (1) the status quo of keeping everything in libswiftCore.dylib or (2) splitting libswiftCore.dylib into two dylibs, one which includes some of the “deprecated” APIs.  I’ll enumerate what I think are the tradeoffs/benefits we will see with both scenarios, and see where the mismatch in our “talking past each other” is happening.


> In both cases (A) and (B), with ABI stability the Standard Library has the option to ship in the OS.  Thus applications using Swift on (say) iOS would no longer need to include libswiftCore.dylib in the app when running on an OS that shipped with the Standard Library.

Right.  Please keep in mind that both approaches also eliminate all the overlay dylibs for those apps, and both approaches put the vast majority of the stdlib code into the OS as well.  The ‘deprecated’ dylib is probably going to be comparatively small.

> With that in mind, here are the tradeoffs as I see between scenarios (A) and (B):
> (A) Status quo: Keep shipping everything in libswiftCore.dylib
> - Applications running on an OS with the Standard Library would no longer have *any* of the currently libswift*.dylib’s embedded inside the application bundle because they would just use the one in the OS.


> - One benefit of using libswift*.dylibs in the OS as opposed to those embedded inside the app bundle is that there is a non-neglible startup time improvement, as the code signing verification that happens when an app launches would be faster as it would not need to verify each of these dylibs that were previously embedded in the app.  We should consider this the new baseline for app startup time for an app running on an OS with an ABI stable Standard Library.

This happens with both models.  Refer back to the dyld optimization WWDC talk by Nick and Louis 2-3 years ago.  The big problem with Swift for startup time is that it adds half a dozen (or more) dylibs to your app bundle.  In the talk they make it clear that adding a single dylib is not a big deal, it is adding a bunch of dylibs that is the problem, particularly if they have interdependencies between them.

Neither approach presents this performance problem.

Further, if it were important to solve this startup time problem, it is straight-forward to solve it for apps that do want to deploy backward (which will be almost all of them in NMOS).  You’d do this by merging all the dylibs into a single one in the app bundle instead of leaving them to be independently resolved at load time.

> - We continue to support the deprecated APIs for some time, possibly indefinitely, even when better alternatives come around.


> (B) Split libswiftCore.dylib into two dylibs, one that gets embedded in the app bundle
> In the second scenario, we split out the deprecated APIs into a separate dylib, say libswiftCoreDeprecated.dylib.  That solution would have the following characteristics:
> - Like scenario (A), app bundles would not need to embed libswiftCore.dylib when running on an OS that had an ABI-stable Standard Library.
> - Compared to scenario (A), the OS shipping the Standard Library would have a slightly smaller libswiftCore.dylib that didn’t carry the bits for the deprecated APIs.  This would be a benefit in the code size for the OS, but not for the app itself.

The code size is small so it doesn’t matter much either way, but this actually is an advantage for the average app.  Part of the point of this is that most apps don’t use this stuff, so they wouldn’t include the dylib at all.  There is no cost for them in either launch time or size.

To pick on Mirrors, the one example someone came up with is an API used by the swift on server community.  I haven’t heard of anyone using them in an iOS app (but of course I’m sure there is someone somewhere doing it :-)

> - Any app using a deprecated API we put into libswiftCoreDeprecated.dylib (e.g., Mirrors) would need to embed libswiftCoreDeprecated.dylib inside their app bundle.  Compared to the new baseline I mentioned in (A), such apps would have a launch time regression once they started using any API in the libSwiftCoreDeprecated.dylib because code signing would need to verify the dylib, just like it does today with the libswiftCore.dylib that is embedded in every application.  They would also be slightly larger because the app bundle has the burden of hosting libswiftCoreDeprecated.dylib, instead of compared to scenario (A) where the implementations of the deprecated APIs are hosted by the libswiftCore.dylib that ships in the OS.

The launch time comes from dyld, not code signing, but yes they would pay a very small cost.  Again, I’d strongly recommend brushing up on nick + louis' WWDC talk that discusses this.

More to the point though, it is *good* that there is some (small) pressure for people to stop using APIs that are deprecated in Swift 5 and earlier.  This is a one time opportunity. :-)

> - Because of binary compatibility concerns, after Swift 5 we would *never* be able to “take out” any further APIs from libswiftCore.dylib and put them in libswiftCoreDeprecated.dylib.  This factorization can only happen once.

Correct, though Xiaodi’s point about gradually easing new APIs in with a similar approach is really really interesting and could be profound.

> - There is some slight additional complexity added to the compiler and build system to support this spit of the Standard Library into multiple dylibs.  It’s not a huge concern but it does exist and it is not free both in terms of implementing and maintaining.

Sure, but it also greatly eliminates the pressure to achieve perfection for a lot of API that simply isn’t important enough to fret that much about.  This pays for itself in schedule time.

> - We continue to support the deprecated APIs for some time, possibly indefinitely, even when better alternatives come around.  We *may* be able to completely sunset these APIs by having a future version of the Swift compiler simply refuse to build projects that use the deprecated (now obsoleted) APIs.  At that point, these apps need to move to using the newer API alternatives, or not upgrade to using a new Swift compiler.

Right: source compatibility isn’t a forever thing, even for existing Objective-C APIs vended by apple.  Giving people (e.g.) 3 years to migrate and remove them would probably be fine.  The key thing is that you never break *already shipped apps*, you only make more work for people who are actively maintaining/updating their app.

> With these points in mind, both scenarios are (by construction) very similar.  

I disagree, because I think you’re misunderstanding the performance impact of adding exactly one dylib to an app bundle.  How many dylibs does Swift 4 typically add to an app?  It’s probably up to 8 or more.

1 dylib isn’t a problem, check with Nick and Louis.

> I have not done the measurements of the impact in code size to the Standard Library of removing Mirrors, but I hypothesize it is relatively modest (I will look at verifying this hypothesis).

I agree.  The major motivation from my side isn’t the code size reduction, it is that we’ll have a better and brighter future with more clarity and less weird cruft left over - like the “DictionaryLiteral” type that sparked this whole thread.  Have you looked at it?  It’s crazy. :-)


More information about the swift-evolution mailing list