[swift-evolution] [RFC] "Library Evolution Support in Swift ('Resilience')"
jgroff at apple.com
Mon Feb 8 21:17:02 CST 2016
> On Feb 8, 2016, at 6:47 PM, Charles Srstka via swift-evolution <swift-evolution at swift.org> wrote:
>> On Feb 8, 2016, at 8:24 PM, Jordan Rose via swift-evolution <swift-evolution at swift.org> wrote:
>> Hi, swift-evolution. We've been making references for a while to "resilience" as a cornerstone of the Swift 3.0 work, the collection of features that allows a library to evolve over time while maintaining binary compatibility. Among other things, this is necessary if we want to stop bundling the Swift standard library with any app that uses Swift, a noted complaint from iOS developers. :-)
>> If you're wondering what this is all about, take a look at the prologue for the design document:
>>> One of Swift’s primary design goals is to allow efficient execution of code without sacrificing load-time abstraction of implementation.
>>> Abstraction of implementation means that code correctly written against a published interface will correctly function when the underlying implementation changes to anything which still satisfies the original interface. There are many potential reasons to provide this sort of abstraction. Apple’s primary interest is in making it easy and painless for our internal and external developers to improve the ecosystem of Apple products by creating good and secure programs and libraries; subtle deployment problems and/or unnecessary dependencies on the behavior of our implementations would work against these goals.
>>> Our current design in Swift is to provide opt-out load-time abstraction of implementation for all language features. Alone, this would either incur unacceptable cost or force widespread opting-out of abstraction. We intend to mitigate this primarily by designing the language and its implementation to minimize unnecessary and unintended abstraction:
>>> • Avoiding unnecessary language guarantees and taking advantage of that flexibility to limit load-time costs.
>>> • Within the domain that defines an entity, all the details of its implementation are available.
>>> • When entities are not exposed outside their defining module, their implementation is not constrained.
>>> • By default, entities are not exposed outside their defining modules. This is independently desirable to reduce accidental API surface area, but happens to also interact well with the performance design.
>>> This last point is a specific case of a general tenet of Swift: the default behavior is safe. Where possible, choices made when an entity is first published should not limit its evolution in the future.
>> RFC stands for "request for comments", and that's what this is: I'd appreciate the eager and discriminating eyes of swift-evolution on this model. It is quite long—nearly ten thousand words—and attempts to be fairly precise in describing what is and isn't allowed, so feel free to focus on the parts that interest you most. This isn't a proposal and won't be going through the Swift Evolution Process, but many existing or planned proposals will affect or support the model described here. (There's a list of them at the end of the document.)
>> The document is written in ReStructuredText to match the rest of the compiler documentation, but it's using some features from the Sphinx system that GitHub's ReST renderer doesn't support. Consequently, I've put up a rendered form, which I'll update every few days when there are changes. (This is pretty much the same rendering you get from running "make" in the docs/ directory in the Swift repo.) The canonical document is still the one in the Swift repository.
>> Looking forward to your feedback!
>> swift-evolution mailing list
>> swift-evolution at swift.org
> I noticed this note in the document:
>> Swift 2’s implementation of default values puts the evaluation of the default value expression in the library, rather than in the client like C++ or C#. We plan to change this.
> What is the reasoning behind this? Keeping the default value in the library seems more resilient; if the default value changes, clients will get the new behavior without requiring a recompile, thus matching the behavior that you’d get if you implemented the same thing via a method with fewer arguments (as you’d have done in Objective-C). This seems far preferable to hard-coding all the default values in the client, IMO.
Abstracting default values from the client limits resilience in other, more obnoxious ways. In particular, it means you can't *introduce* new defaulted parameters on published APIs without a deployment target limitation, since the entry point for the default argument evaluator will be missing in older versions. We figured that instantiating the default argument on the client side is more in line with users' expectations in what resilience constraints it imposes. In many cases, you'll have the resilinece you want at a different level; for example, in the common case of an option set where the default is 'all options', evaluating 'func foo(options: Options = .all)' is still resilient if 'Options.all' is.
More information about the swift-evolution