<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Feb 20, 2017, at 3:40 AM, Florent Bruneau <<a href="mailto:florent.bruneau@intersec.com" class="">florent.bruneau@intersec.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi John,<br class=""><br class="">I've spent 3 hours reading the manifesto and its really very interesting. Despite the completeness of the included discussion, I have a few comments/concerns.<br class=""><br class=""><br class="">The first one is about the use a Copyable protocol whose conformance must be explicit in the module of the definition of the type. Since copyability shouldn't be modified outside the module that define a type, using a protocol seems a bit weird since AFAIK no other protocol has this kind of constraints. I do understand this enables some idiomatic constructs (like you example where Array conforms to Copyable whenever its elements are copyable), but on the other hand this looks a bit confusing to me. I don't have a better solution, thought.<br class=""></div></div></blockquote><div><br class=""></div>On the one hand, I agree that it's not quite a normal protocol. On the other hand... it's a capability of a type, which is the sort of thing we normally express with a protocol. And because it's not just a single bit — because a generic type can conditionally have that capability — if we made it not a protocol, we'd just have to re-invent a new mechanism to declare that, which would effectively be exactly like the protocol mechanism.</div><div><br class=""></div><div>I think it's much simpler to say that certain protocols are "policy" protocols which are solely up to the author of the type to decide, and that external, "retroactive" conformance is only allowed for non-policy protocols.</div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div class="">Secondly, in your discussion about variable independence, you talk about logical dependence: variables that are part of the same container. However, whenever this is some concurrency involved, there is also some kind of physical dependence. If you have two values stored physically in memory in the same cache line, and you may want to modify both independently and concurrently (one thread modifies the first value, the second modifies the other one), you have some false sharing which impacts the performance since the actual writes get sequentialized at CPU level. Is there any plan to take this kind of dependencies into account?<br class=""></div></div></blockquote><div><br class=""></div>Well, for one, CPUs may get cleverer here over time. So I would be uncomfortable with cementing this too much in the language.</div><div><br class=""></div><div>The bigger issue is that we don't have a mechanism for positively declaring that two variables will be accessed from different threads. It would be disastrous to over-interpret the *possibility* of concurrent access on different class properties as a statement of *probability* of concurrent access — because the only option there would be, what, to put each property on its own cache line? And cache line sizes change, so this is not statically knowable.</div><div><br class=""></div><div>I think it's fine for us to design the implementation around the idea that it's not necessarily a good idea to access different properties concurrently — that's true semantically, not just for performance, because obviously that kind of concurrent access to a class takes a lot more care and attention to get right — and leave it up to the programmer to respond.</div><div><br class=""></div><div>Allowing some sort of intelligent layout to prevent cache-line collisions would certainly be a secondary goal of a concurrency design, though.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class="">Thirdly, I'm a bit worried about the runtime impact of the dynamic enforcement of the law of exclusivity. It seems to me that in many use cases we will fall back to the dynamic enforcement because of the language is too dynamic to allow static enforcement. As discussed in the manifesto, it's not desirable (not doable) to put the full concept of ownership and lifetime in the type system. However, I cannot see how interaction between objects will work in the current approach. Let suppose I have a concurrent application that have a shared ressource that can be used by various workers. Workers can be either structures/classes or closures.<br class=""><br class="">```swift<br class="">struct Ressource {<br class=""> /* content is unimportant here */<br class="">}<br class=""><br class="">class Worker {<br class=""> shared ressource: Ressource<br class=""><br class=""> init(ressource: shared Ressource) {<br class=""> self.ressource = ressource<br class=""> }<br class=""><br class=""> /* ... */<br class="">}<br class=""><br class="">let ressource = Ressource()<br class=""><br class="">for i in 0..<10 {<br class=""> let worker = Worker(ressource: ressource)<br class=""> worker.schedule()<br class="">}<br class="">waitAllWorkers()<br class="">```<br class=""><br class="">My understanding of the manifesto is that this kind of construct in not really part of it. Is there a way to enforce the workers' lifetime to be shorter than the lifetime of the ressource?<br class=""></div></div></blockquote><div><br class=""></div>If we had the ability to express "shared resource: Resource" as a class property, yes, but you're correct that this is not currently allowed in the design. That's mostly a limitation of *static* enforcement, though, because we need to always be statically limiting the durations of ephemerals, and having that transitively limit the lifetime of a class instance is quite complicated.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class="">Finally, since I work a lot with imported C code, I'd like to know if there is some plan to make the ownership attributes works well with C code. I mean, you say that unsafe pointers just force a fall back to not enforcing the law of exclusivity, but in my day-to-day work, this is exactly where I need it the most: when I have to manipulate a structure that contain a pointer allocated by some C code, I cannot allow copy of that structure since that pointer may be reallocated and one of the copies would contain a dangling pointer. So, is there some way to opt-in for non-copyability of imported code?<br class=""></div></div></blockquote><div><br class=""></div><div>Well, copying the C structure isn't directly problematic in your case because there's no automatic management of the pointer, but I see your point that it can be an indirect problem because you might e.g. add a method to the imported type which internally manages the pointer. It does seem reasonable to have an attribute you can use in C that would tell Swift to import something as a non-copyable type.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">I tried, without success, to propose some way to improve pointer-passing between C and Swift [1] that could help tracking ownership when interacting with C code.<br class=""><br class="">[1] <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170130/031199.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170130/031199.html</a><br class=""></div></div></blockquote><div><br class=""></div>I think it's mostly that this is a really big topic and we're already worried about how much we're doing in the next few months. Even just the language-review aspect of a proposal like that would be an intimidatingly broad commitment.</div><div><br class=""></div><div>When ownership is in place, we will at least have the right language tools for theoretically, say, always importing pointers to a particular type as a managed unique-reference type. So this is a major step in that direction.</div><div><br class=""></div><div>John.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class=""><br class=""><blockquote type="cite" class="">Le 17 févr. 2017 à 09:25, John McCall via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> a écrit :<br class=""><br class="">Hello, swift-evolution.<br class=""><br class="">Memory ownership is a topic that keeps poking its head up here. Core team<br class="">members have mentioned several times that it's something we're interested in<br class="">working on. Questions sometimes get referred back to it, saying stuff like<br class="">"we're working on tools to let you control ARC a little better". It's even on the<br class="">short list of high-priority features for Swift 4:<br class=""><br class=""> <a href="https://github.com/apple/swift-evolution" class="">https://github.com/apple/swift-evolution</a><br class=""><br class=""> Memory ownership model: an (opt-in) Cyclone/Rust-inspired memory<br class=""> ownership model is highly desired by systems programmers and for other<br class=""> high-performance applications that want predictable and deterministic<br class=""> performance. This feature will fundamentally shape the ABI, from low-level<br class=""> language concerns such as "inout" and low-level "addressors" to its impact<br class=""> on the standard library. While a full memory ownership model is likely too<br class=""> large for Swift 4 stage 1, we need a comprehensive design to understand<br class=""> how it will change the ABI.<br class=""><br class="">But that's all pretty vague. What is ownership? What does it mean for<br class="">programmers? Is somebody ever going to actually write that comprehensive<br class="">design that was supposed to come out during Stage 1?<br class=""><br class="">Well, here you go.<br class=""><br class="">I want to emphasize that this document is two things. It is a *manifesto*,<br class="">because it describes the whole problem and presents a holistic solution to it.<br class="">And it is a *meta-proposal*, because that holistic solution imagines and a number<br class="">of changes, each of which is worthy of a proposal; it is, essentially, a proposal<br class="">that we write a bunch of smaller proposals for each of these changes. But it's<br class="">not actually a concrete proposal for those smaller changes: it's often lacking in<br class="">that level of detail, and it leaves a number of questions open. This document, itself,<br class="">will not undergo the formal evolution process. And it may be that some of these<br class="">changes aren't really necessary, or that they need major reconsideration before<br class="">they're appropriate for proposal. But our hope — my hope — is that this<br class="">document is sufficient for you to understand the holistic approach we're suggesting,<br class="">or at least puts you in a position where you're comfortable asking questions<br class="">and trying to figure it out.<br class=""><br class="">So, like I said, this isn't a formal proposal. What, then, are we hoping to achieve?<br class="">Well, we want people to talk about it. We'd like to achieve a consensus about<br class="">whether this basic approach makes sense for the language and achieves its goals.<br class="">And, assuming that the consensus is "yes" and that we should go forward with it,<br class="">we'd like this document — and this thread — to serve as an introduction to the<br class="">topic that we can refer back to when we're proposing and discussing all of those<br class="">changes in the weeks to come.<br class=""><br class="">With that said, let's get started.<br class=""><br class="">John.<br class=""><br class="">------------------------------------------------------------------<br class=""><br class=""># Ownership<br class=""><br class="">## Introduction<br class=""><br class="">Adding "ownership" to Swift is a major feature with many benefits<br class="">for programmers. This document is both a "manifesto" and a<br class="">"meta-proposal" for ownership: it lays out the basic goals of<br class="">the work, describes a general approach for achieving those goals,<br class="">and proposes a number of specific changes and features, each of<br class="">which will need to be separately discussed in a smaller and more<br class="">targeted proposal. This document is intended to provide a framework<br class="">for understanding the contributions of each of those changes.<br class=""><br class="">### Problem statement<br class=""><br class="">The widespread use of copy-on-write value types in Swift has generally<br class="">been a success. It does, however, come with some drawbacks:<br class=""><br class="">* Reference counting and uniqueness testing do impose some overhead.<br class=""><br class="">* Reference counting provides deterministic performance in most cases,<br class=""> but that performance can still be complex to analyze and predict.<br class=""><br class="">* The ability to copy a value at any time and thus "escape" it forces<br class=""> the underlying buffers to generally be heap-allocated. Stack allocation<br class=""> is far more efficient but does require some ability to prevent, or at<br class=""> least recognize, attempts to escape the value.<br class=""><br class="">Certain kinds of low-level programming require stricter performance<br class="">guarantees. Often these guarantees are less about absolute performance<br class="">than *predictable* performance. For example, keeping up with an audio<br class="">stream is not a taxing job for a modern processor, even with significant<br class="">per-sample overheads, but any sort of unexpected hiccup is immediately<br class="">noticeable by users.<br class=""><br class="">Another common programming task is to optimize existing code when something<br class="">about it falls short of a performance target. Often this means finding<br class="">"hot spots" in execution time or memory use and trying to fix them in some<br class="">way. When those hot spots are due to implicit copies, Swift's current<br class="">tools for fixing the problem are relatively poor; for example, a programmer<br class="">can fall back on using unsafe pointers, but this loses a lot of the<br class="">safety benefits and expressivity advantages of the library collection types.<br class=""><br class="">We believe that these problems can be addressed with an opt-in set of<br class="">features that we collectively call *ownership*.<br class=""><br class="">### What is ownership?<br class=""><br class="">*Ownership* is the responsibility of some piece of code to<br class="">eventually cause a value to be destroyed. An *ownership system*<br class="">is a set of rules or conventions for managing and transferring<br class="">ownership.<br class=""><br class="">Any language with a concept of destruction has a concept of<br class="">ownership. In some languages, like C and non-ARC Objective-C,<br class="">ownership is managed explicitly by programmers. In other<br class="">languages, like C++ (in part), ownership is managed by the<br class="">language. Even languages with implicit memory management still<br class="">have libraries with concepts of ownership, because there are<br class="">other program resources besides memory, and it is important<br class="">to understand what code has the responsibility to release<br class="">those resources.<br class=""><br class="">Swift already has an ownership system, but it's "under the covers":<br class="">it's an implementation detail that programmers have little<br class="">ability to influence. What we are proposing here is easy<br class="">to summarize:<br class=""><br class="">- We should add a core rule to the ownership system, called<br class=""> the Law of Exclusivity, which requires the implementation<br class=""> to prevent variables from being simultaneously accessed<br class=""> in conflicting ways. (For example, being passed `inout`<br class=""> to two different functions.) This will not be an opt-in<br class=""> change, but we believe that most programs will not be<br class=""> adversely affected.<br class=""><br class="">- We should add features to give programmers more control over<br class=""> the ownership system, chiefly by allowing the propagation<br class=""> of "shared" values. This will be an opt-in change; it<br class=""> will largely consist of annotations and language features<br class=""> which programmers can simply not use.<br class=""><br class="">- We should add features to allow programmers to express<br class=""> types with unique ownership, which is to say, types that<br class=""> cannot be implicitly copied. This will be an opt-in<br class=""> feature intended for experienced programmers who desire<br class=""> this level of control; we do not intend for ordinary<br class=""> Swift programming to require working with such types.<br class=""><br class="">These three tentpoles together have the effect of raising<br class="">the ownership system from an implementation detail to a more<br class="">visible aspect of the language. They are also somewhat<br class="">inseparable, for reasons we'll explain, although of course they<br class="">can be prioritized differently. For these reasons, we will<br class="">talk about them as a cohensive feature called "ownership".<br class=""><br class="">### A bit more detail<br class=""><br class="">The basic problem with Swift's current ownership system<br class="">is copies, and all three tentpoles of ownership are about<br class="">avoiding copies.<br class=""><br class="">A value may be used in many different places in a program.<br class="">The implementation has to ensure that some copy of the value<br class="">survives and is usable at each of these places. As long as<br class="">a type is copyable, it's always possible to satisfy that by<br class="">making more copies of the value. However, most uses don't<br class="">actually require ownership of their own copy. Some do: a<br class="">variable that didn't own its current value would only be<br class="">able to store values that were known to be owned by something<br class="">else, which isn't very useful in general. But a simple thing<br class="">like reading a value out of a class instance only requires that<br class="">the instance still be valid, not that the code doing the<br class="">read actually own a reference to it itself. Sometimes the<br class="">difference is obvious, but often it's impossible to know.<br class="">For example, the compiler generally doesn't know how an<br class="">arbitrary function will use its arguments; it just falls<br class="">back on a default rule for whether to pass ownership of<br class="">the value. When that default rule is wrong, the program<br class="">will end up making extra copies at runtime. So one simple<br class="">thing we can do is allow programs to be more explicit at<br class="">certain points about whether they need ownership or not.<br class=""><br class="">That closely dovetails with the desire to support non-copyable<br class="">types. Most resources require a unique point of destruction:<br class="">a memory allocation can only be freed once, a file can only<br class="">be closed once, a lock can only be released once, and so on.<br class="">An owning reference to such a resource is therefore naturally<br class="">unique and thus non-copyable. Of course, we can artificially<br class="">allow ownership to be shared by, say, adding a reference count<br class="">and only destroying the resource when the count reaches zero.<br class="">But this can substantially increase the overhead of working<br class="">with the resource; and worse, it introduces problems with<br class="">concurrency and re-entrancy. If ownership is unique, and the<br class="">language can enforce that certain operations on a resource<br class="">can only be performed by the code that owns the resource,<br class="">then by construction only one piece of code can perform those<br class="">operations at a time. As soon as ownership is shareable,<br class="">that property disappears. So it is interesting for the<br class="">language to directly support non-copyable types because they<br class="">allow the expression of optimally-efficient abstractions<br class="">over resources. However, working with such types requires<br class="">all of the abstraction points like function arguments to<br class="">be correctly annotated about whether they transfer ownership,<br class="">because the compiler can no longer just make things work<br class="">behind the scenes by adding copies.<br class=""><br class="">Solving either of these problems well will require us to<br class="">also solve the problem of non-exclusive access to variables.<br class="">Swift today allows nested accesses to the same variable;<br class="">for example, a single variable can be passed as two different<br class="">`inout` arguments, or a method can be passed a callback that<br class="">somehow accesses the same variable that the method was called on.<br class="">Doing this is mostly discouraged, but it's not forbidden,<br class="">and both the compiler and the standard library have to bend<br class="">over backwards to ensure that the program won't misbehave<br class="">too badly if it happens. For example, `Array` has to retain<br class="">its buffer during an in-place element modification; otherwise,<br class="">if that modification somehow reassigned the array variable,<br class="">the buffer would be freed while the element was still being<br class="">changed. Similarly, the compiler generally finds it difficult<br class="">to prove that values in memory are the same at different points<br class="">in a function, because it has to assume that any opaque<br class="">function call might rewrite all memory; as a result, it<br class="">often has to insert copies or preserve redundant loads<br class="">out of paranoia. Worse, non-exclusive access greatly<br class="">limits the usefulness of explicit annotations. For example,<br class="">a "shared" argument is only useful if it's really guaranteed<br class="">to stay valid for the entire call, but the only way to<br class="">reliably satisfy that for the current value of a variable<br class="">that can be re-entrantly modified is to make a copy and pass<br class="">that instead. It also makes certain important patterns<br class="">impossible, like stealing the current value of a variable<br class="">in order to build something new; this is unsound if the<br class="">variable can be accessed by other code in the middle.<br class="">The only solution to this is to establish a rule that prevents<br class="">multiple contexts from accessing the same variable at the<br class="">same time. This is what we propose to do with the Law<br class="">of Exclusivity.<br class=""><br class="">All three of these goals are closely linked and mutually<br class="">reinforcing. The Law of Exclusivity allows explicit annotations<br class="">to actually optimize code by default and enables mandatory<br class="">idioms for non-copyable types. Explicit annotations create<br class="">more optimization opportunities under the Law and enable<br class="">non-copyable types to function. Non-copyable types validate<br class="">that annotations are optimal even for copyable types and<br class="">create more situations where the Law can be satisfied statically.<br class=""><br class="">### Criteria for success<br class=""><br class="">As discussed above, it is the core team's expectation that<br class="">ownership can be delivered as an opt-in enhancement to Swift.<br class="">Programmers should be able to largely ignore ownership and not<br class="">suffer for it. If this expectation proves to not be satisfiable,<br class="">we will reject ownership rather than imposing substantial<br class="">burdens on regular programs.<br class=""><br class="">The Law of Exclusivity will impose some new static and dynamic<br class="">restrictions. It is our belief that these restrictions will only<br class="">affect a small amount of code, and only code that does things<br class="">that we already document as producing unspecified results.<br class="">These restrictions, when enforced dynamically, will also hurt<br class="">performance. It is our hope that this will be "paid for" by<br class="">the improved optimization potential. We will also provide tools<br class="">for programmers to eliminate these safety checks where necessary.<br class="">We will discuss these restrictions in greater detail later in this<br class="">document.<br class=""><br class="">## Core definitions<br class=""><br class="">### Values<br class=""><br class="">Any discussion of ownership systems is bound to be at a lower<br class="">level of abstraction. We will be talking a lot about<br class="">implementation topics. In this context, when we say "value",<br class="">we mean a specific instance of a semantic, user-language value.<br class=""><br class="">For example, consider the following Swift code:<br class=""><br class="">```<br class=""> var x = [1,2,3]<br class=""> var y = x<br class="">```<br class=""><br class="">People would often say that `x` and `y` have the same value<br class="">at this point. Let's call this a *semantic value*. But at<br class="">the level of the implementation, because the variables `x` and `y`<br class="">can be independently modified, the value in `y` must be a<br class="">copy of the value in `x`. Let's call this a *value instance*.<br class="">A value instance can be moved around in memory and remain the<br class="">same value instance, but a copy always yields a new value instance.<br class="">For the remainder of this document, when we use "value" without any<br class="">qualification, we mean it in this low-level sense of value instance.<br class=""><br class="">What it means to copy or destroy a value instance depends on the type:<br class=""><br class="">* Some types do not require extra work besides copying their<br class=""> byte-representation; we call these *trivial*. For example,<br class=""> `Int` and `Float` are trivial types, as are ordinary `struct`s<br class=""> and `enum`s containing only such values. Most of what we have<br class=""> to say about ownership in this document doesn't apply to the<br class=""> values of such types. However, the Law of Exclusivity will still<br class=""> apply to them.<br class=""><br class="">* For reference types, the value instance is a reference to an object.<br class=""> Copying the value instance means making a new reference, which<br class=""> increases the reference count. Destroying the value instance means<br class=""> destroying a reference, which decreases the reference count. Decreasing<br class=""> the reference count can, of course, drop it to zero and thus destroy<br class=""> the object, but it's important to remember that all this talk about<br class=""> copying and destroying values means manipulating reference counts,<br class=""> not copying the object or (necessarily) destroying it.<br class=""><br class="">* For copy-on-write types, the value instance includes a reference to<br class=""> a buffer, which then works basically like a reference type. Again,<br class=""> it is important to remember that copying the value doesn't mean<br class=""> copying the contents of the buffer into a new buffer.<br class=""><br class="">There are similar rules for every kind of type.<br class=""><br class="">### Memory<br class=""><br class="">In general, a value can be owned in one of two ways: it can be<br class="">"in flight", a temporary value owned by a specific execution context<br class="">which computed the value as an operand, or it can be "at rest",<br class="">stored in some sort of memory.<br class=""><br class="">We don't need to focus much on temporary values because their<br class="">ownership rules are straightforward. Temporary values are created<br class="">as the result of some expression; that expression is used in some<br class="">specific place; the value is needed in that place and not<br class="">thereafter; so the implementation should clearly take all possible<br class="">steps to forward the value directly to that place instead of<br class="">forcing it to be copied. Users already expect all of this to<br class="">happen, and there's nothing really to improve here.<br class=""><br class="">Therefore, most of our discussion of ownership will center around<br class="">values stored in memory. There are five closely related concepts<br class="">in Swift's treatment of memory.<br class=""><br class="">A *storage declaration* is the language-syntax concept of a declaration<br class="">that can be treated in the language like memory. Currently, these are<br class="">always introduced with `let`, `var`, and `subscript`. A storage<br class="">declaration has a type. It also has an implementation which defines<br class="">what it means to read or write the storage. The default implementation<br class="">of a `var` or `let` just creates a new variable to store the value,<br class="">but storage declarations can also be computed, and so there needn't<br class="">be any variables at all behind one.<br class=""><br class="">A *storage reference expression* is the syntax concept of an expression<br class="">that refers to storage. This is similar to the concept from other<br class="">languages of an "l-value", except that it isn't necessarily usable on<br class="">the left side of an assignment because the storage doesn't have to be<br class="">mutable.<br class=""><br class="">A *storage reference* is the language-semantics concept of a fully<br class="">filled-in reference to a specific storage declaration. In other<br class="">words, it is the result of evaluating a storage reference expression<br class="">in the abstract, without actually accessing the storage. If the<br class="">storage is a member, this includes a value or storage reference<br class="">for the base. If the storage is a subscript, this includes a value<br class="">for the index. For example, a storage reference expression like<br class="">`widgets[i].weight` might abstractly evaluate to this storage reference:<br class=""><br class="">* the storage for the property `var weight: Double` of<br class="">* the storage for the subscript `subscript(index: Int)` at index value `19: Int` of<br class="">* the storage for the local variable `var widgets: [Widget]`<br class=""><br class="">A *variable* is the semantics concept of a unique place in<br class="">memory that stores a value. It's not necessarily mutable, at least<br class="">as we're using it in this document. Variables are usually created for<br class="">storage declarations, but they can also be created dynamically in<br class="">raw memory, e.g. using UnsafeRawPointer. A variable always has a<br class="">specific type. It also has a *lifetime*, i.e. a point in the language<br class="">semantics where it comes into existence and a point (or several)<br class="">where it is destroyed.<br class=""><br class="">A *memory location* is a contiguous range of addressable memory. In<br class="">Swift, this is mostly an implementation concept. Swift does not<br class="">guarantee that any particular variable will have a consistent memory<br class="">location throughout its lifetime, or in fact be stored in a memory<br class="">location at all. But a variable can sometimes be temporarily forced<br class="">to exist at a specific, consistent location: e.g. it can be passed<br class="">`inout` to `withUnsafeMutablePointer`.<br class=""><br class="">### Accesses<br class=""><br class="">A particular evaluation of a storage reference expression is<br class="">called an access. Accesses come in three kinds: *reads*,<br class="">*assignments*, and *modifications*. Assignments and modifications<br class="">are both *writes*, with the difference being that an assignment<br class="">completely replaces the old value without reading it, while a<br class="">modification does rely on the old value.<br class=""><br class="">All storage reference expressions are classified into one of these<br class="">three kinds of access based on the context in which the expression<br class="">appears. It is important to note that this decision is superficial:<br class="">it relies only on the semantic rules of the immediate context, not<br class="">on a deeper analysis of the program or its dynamic behavior.<br class="">For example, a storage reference passed as an `inout` argument<br class="">is always evaluated as a modification in the caller, regardless<br class="">of whether the callee actually uses the current value, performs<br class="">any writes to it, or even refers to it at all.<br class=""><br class="">The evaluation of a storage reference expression is divided into<br class="">two phases: it is first formally evaluated to a storage reference,<br class="">and then a formal access to that storage reference occurs for some<br class="">duration. The two phases are often evaluated in immediate<br class="">succession, but they can be separated in complex cases, such as<br class="">when an `inout` argument is not the last argument to a call.<br class="">The purpose of this phase division is to minimize the duration of<br class="">the formal access while still preserving, to the greatest extent<br class="">possible, Swift's left-to-right evaluation rules.<br class=""><br class="">## The Law of Exclusivity<br class=""><br class="">With all of that established, we can succinctly state the first<br class="">part of this proposal, the Law of Exclusivity:<br class=""><br class=""><blockquote type="cite" class="">If a storage reference expression evaluates to a storage<br class="">reference that is implemented by a variable, then the formal<br class="">access duration of that access may not overlap the formal<br class="">access duration of any other access to the same variable<br class="">unless both accesses are reads.<br class=""></blockquote><br class="">This is intentionally vague: it merely says that accesses<br class="">"may not" overlap, without specifying how that will be<br class="">enforced. This is because we will use different enforcement<br class="">mechanisms for different kinds of storage. We will discuss<br class="">those mechanisms in the next major section. First, however,<br class="">we need to talk in general about some of the implications of<br class="">this rule and our approach to satisfying it.<br class=""><br class="">### Duration of exclusivity<br class=""><br class="">The Law says that accesses must be exclusive for their entire<br class="">formal access duration. This duration is determined by the<br class="">immediate context which causes the access; that is, it's a<br class="">*static* property of the program, whereas the safety problems<br class="">we laid out in the introduction are *dynamic*. It is a general<br class="">truth that static approaches to dynamic problems can only be<br class="">conservatively correct: there will be dynamically-reasonable<br class="">programs that are nonetheless rejected. It is fair to ask how<br class="">that general principle applies here.<br class=""><br class="">For example, when storage is passed as an `inout` argument, the<br class="">access lasts for the duration of the call. This demands<br class="">caller-side enforcement that no other accesses can occur to<br class="">that storage during the call. Is it possible that this is too<br class="">coarse-grained? After all, there may be many points within the<br class="">called function where it isn't obviously using its `inout`<br class="">argument. Perhaps we should track accesses to `inout` arguments<br class="">at a finer-grained level, within the callee, instead of attempting<br class="">to enforce the Law of Exclusivity in the caller. The problem<br class="">is that that idea is simply too dynamic to be efficiently<br class="">implemented.<br class=""><br class="">A caller-side rule for `inout` has one key advantage: the<br class="">caller has an enormous amount of information about what<br class="">storage is being passed. This means that a caller-side rule<br class="">can often be enforced purely statically, without adding dynamic<br class="">checks or making paranoid assumptions. For example, suppose<br class="">that a function calls a `mutating` method on a local variable.<br class="">(Recall that `mutating` methods are passed `self` as an `inout`<br class="">argument.) Unless the variable has been captured in an<br class="">escaping closure, the function can easily examine every<br class="">access to the variable to see that none of them overlap<br class="">the call, thus proving that the rule is satisfied. Moreover,<br class="">that guarantee is then passed down to the callee, which can<br class="">use that information to prove the safety of its own accesses.<br class=""><br class="">In contrast, a callee-side rule for `inout` cannot take<br class="">advantage of that kind of information: the information is<br class="">simply discarded at the point of the call. This leads to the<br class="">widespread optimization problems that we see today, as<br class="">discussed in the introduction. For example, suppose that<br class="">the callee loads a value from its argument, then calls<br class="">a function which the optimizer cannot reason about:<br class=""><br class="">```<br class=""> extension Array {<br class=""> mutating func organize(_ predicate: (Element) -> Bool) {<br class=""> let first = self[0]<br class=""> if !predicate(first) { return }<br class=""> ...<br class=""> // something here uses first<br class=""> }<br class=""> }<br class="">```<br class=""><br class="">Under a callee-side rule, the optimizer must copy `self[0]`<br class="">into `first` because it must assume (paranoidly) that<br class="">`predicate` might somehow turn around and modify the<br class="">variable that `self` was bound to. Under a caller-side<br class="">rule, the optimizer can use the copy of value held in the<br class="">array element for as long as it can continue to prove that<br class="">the array hasn't been modified.<br class=""><br class="">Moreover, as the example above suggests, what sort of code<br class="">would we actually be enabling by embracing a callee-side rule?<br class="">A higher-order operation like this should not have to worry<br class="">about the caller passing in a predicate that re-entrantly<br class="">modifies the array. Simple implementation choices, like<br class="">making the local variable `first` instead of re-accessing<br class="">`self[0]` in the example above, would become semantically<br class="">important; maintaining any sort of invariant would be almost<br class="">inconceivable. It is no surprise that Swift's libraries<br class="">generally forbid this kind of re-entrant access. But,<br class="">since the library can't completely prevent programmers<br class="">from doing it, the implementation must nonetheless do extra<br class="">work at runtime to prevent such code from running into<br class="">undefined behavior and corrupting the process. Because it<br class="">exists solely to work around the possibility of code that<br class="">should never occur in a well-written program, we see this<br class="">as no real loss.<br class=""><br class="">Therefore, this proposal generally proposes access-duration<br class="">rules like caller-side `inout` enforcement, which allow<br class="">substantial optimization opportunities at little semantic<br class="">cost.<br class=""><br class="">### Components of value and reference types<br class=""><br class="">We've been talking about *variables* a lot. A reader might<br class="">reasonably wonder what all this means for *properties*.<br class=""><br class="">Under the definition we laid out above, a property is a<br class="">storage declaration, and a stored property creates a<br class="">corresponding variable in its container. Accesses to that<br class="">variable obviously need to obey the Law of Exclusivity, but are<br class="">there any additional restrictions in play due to the fact<br class="">that the properties are organized together into a container?<br class="">In particular, should the Law of Exclusivity prevent accesses<br class="">to different properties of the same variable or value from<br class="">overlapping?<br class=""><br class="">Properties can be classified into three groups:<br class="">- instance properties of value types,<br class="">- instance properties of reference types, and<br class="">- `static` and `class` properties on any kind of type.<br class=""><br class="">We propose to always treat reference-type and `static` properties<br class="">as independent from one another other, but to treat value-type<br class="">properties as generally non-independent outside of a specific<br class="">(but important) special case. That's a potentially significant<br class="">restriction, and it's reasonable to wonder both why it's necessary<br class="">and why we need to draw this distinction between different<br class="">kinds of property. There are three reasons.<br class=""><br class="">#### Independence and containers<br class=""><br class="">The first relates to the container.<br class=""><br class="">For value types, it is possible to access both an individual<br class="">property and the entire aggregate value. It is clear that an<br class="">access to a property can conflict with an access to the aggregate,<br class="">because an access to the aggregate is essentially an access to<br class="">all of the properties at once. For example, consider a variable<br class="">(not necessarily a local one) `p: Point` with stored properties<br class="">`x`, `y`, and `z`. If it were possible to simultaneously and<br class="">independently modify `p` and `p.x`, that would be an enormous<br class="">hole in the Law of Exclusivity. So we do need to enforce the<br class="">Law somehow here. We have three options.<br class=""><br class="">(This may make more sense after reading the main section<br class="">about enforcing the Law.)<br class=""><br class="">The first option is to simply treat `p.x` as also an access to `p`.<br class="">This neatly eliminates the hole because whatever enforcement<br class="">we're using for `p` will naturally prevent conflicting accesses<br class="">to it. But this will also prevent accesses to different<br class="">properties from overlapping, because each will cause an access<br class="">to `p`, triggering the enforcement.<br class=""><br class="">The other two options involve reversing that relationship.<br class="">We could split enforcement out for all the individual stored<br class="">properties, not for the aggregate: an access to `p` would be<br class="">treated as an access to `p.x`, `p.y`, and `p.z`. Or we could<br class="">parameterize enforcement and teach it to record the specific<br class="">path of properties being accessed: "", ".x", and so on.<br class="">Unfortunately, there are two problems with these schemes.<br class="">The first is that we don't always know the full set of<br class="">properties, or which properties are stored; the implementation<br class="">of a type might be opaque to us due to e.g. generics or<br class="">resilience. An access to a computed property must be treated<br class="">as an access to the whole value because it involves passing<br class="">the variable to a getter or setter either `inout` or `shared`;<br class="">thus it does actually conflict with all other properties.<br class="">Attempting to make things work despite that by using dynamic<br class="">information would introduce ubiquitous bookkeeping into<br class="">value-type accessors, endangering the core design goal of<br class="">value types that they serve as a low-cost abstraction tool.<br class="">The second is that, while these schemes can be applied to<br class="">static enforcement relatively easily, applying them to<br class="">dynamic enforcement would require a fiendish amount of<br class="">bookkeeping to be carried out dynamically; this is simply<br class="">not compatible with our performance goals.<br class=""><br class="">Thus, while there is a scheme which allows independent access<br class="">to different properties of the same aggregate value, it<br class="">requires us to be using static enforcement for the aggregate<br class="">access and to know that both properties are stored. This is an<br class="">important special case, but it is just a special case.<br class="">In all other cases, we must fall back on the general rule<br class="">that an access to a property is also an access to the aggregate.<br class=""><br class="">These considerations do not apply to `static` properties and<br class="">properties of reference types. There are no language constructs<br class="">in Swift which access every property of a class simultaneously,<br class="">and it doesn't even make sense to talk about "every" `static`<br class="">property of a type because an arbitrary module can add a new<br class="">one at any time.<br class=""><br class="">#### Idioms of independent access<br class=""><br class="">The second relates to user expectations.<br class=""><br class="">Preventing overlapping accesses to different properties of a<br class="">value type is at most a minor inconvenience. The Law of Exclusivity<br class="">prevents "spooky action at a distance" with value types anyway:<br class="">for example, calling a method on a variable cannot kick off a<br class="">non-obvious sequence of events which eventually reach back and<br class="">modify the original variable, because that would involve two<br class="">conflicting and overlapping accesses to the same variable.<br class=""><br class="">In contrast, many established patterns with reference types<br class="">depend on exactly that kind of notification-based update. In<br class="">fact, it's not uncommon in UI code for different properties of<br class="">the same object to be modified concurrently: one by the UI and<br class="">the other by some background operation. Preventing independent<br class="">access would break those idioms, which is not acceptable.<br class=""><br class="">As for `static` properties, programmers expect them to be<br class="">independent global variables; it would make no sense for<br class="">an access to one global to prevent access to another.<br class=""><br class="">#### Independence and the optimizer<br class=""><br class="">The third relates to the optimization potential of properties.<br class=""><br class="">Part of the purpose of the Law of Exclusivity is that it<br class="">allows a large class of optimizations on values. For example,<br class="">a non-`mutating` method on a value type can assume that `self`<br class="">remains exactly the same for the duration of the method. It<br class="">does not have to worry that an unknown function it calls<br class="">in the middle will somehow reach back and modify `self`,<br class="">because that modification would violate the Law. Even in a<br class="">`mutating` method, no code can access `self` unless the<br class="">method knows about it. Those assumptions are extremely<br class="">important for optimizing Swift code.<br class=""><br class="">However, these assumptions simply cannot be done in general<br class="">for the contents of global variables or reference-type<br class="">properties. Class references can be shared arbitrarily,<br class="">and the optimizer must assume that an unknown function<br class="">might have access to the same instance. And any code in<br class="">the system can potentially access a global variable (ignoring<br class="">access control). So the language implementation would<br class="">gain little to nothing from treating accesses to different<br class="">properties as non-independent.<br class=""><br class="">#### Subscripts<br class=""><br class="">Much of this discussion also applies to subscripts, though<br class="">in the language today subscripts are never technically stored.<br class="">Accessing a component of a value type through a subscript<br class="">is treated as accessing the entire value, and so is considered<br class="">to overlap any other access to the value. The most important<br class="">consequence of this is that two different array elements cannot<br class="">be simultaneously accessed. This will interfere with certain<br class="">common idioms for working with arrays, although some cases<br class="">(like concurrently modifying different slices of an array)<br class="">are already quite problematic in Swift. We believe that we<br class="">can mitigate the majority of the impact here with targetted<br class="">improvements to the collection APIs.<br class=""><br class="">## Enforcing the Law of Exclusivity<br class=""><br class="">There are three available mechanisms for enforcing the Law of<br class="">Exclusivity: static, dynamic, and undefined. The choice<br class="">of mechanism must be decidable by a simple inspection of the<br class="">storage declaration, because the definition and all of its<br class="">direct accessors must agree on how it is done. Generally,<br class="">it will be decided by the kind of storage being declared,<br class="">its container (if any), and any attributes that might be<br class="">present.<br class=""><br class="">### Static enforcement<br class=""><br class="">Under static enforcement, the compiler detects that the<br class="">law is being violated and reports an error. This is the<br class="">preferred mechanism where possible because it is safe, reliable,<br class="">and imposes no runtime costs.<br class=""><br class="">This mechanism can only be used when it is perfectly decidable.<br class="">For example, it can be used for value-type properties because<br class="">the Law, recursively applied, ensures that the base storage is<br class="">being exclusively accessed. It cannot be used for ordinary<br class="">reference-type properties because there is no way to prove in<br class="">general that a particular object reference is the unique<br class="">reference to an object. However, if we supported<br class="">uniquely-referenced class types, it could be used for their<br class="">properties.<br class=""><br class="">In some cases, where desired, the compiler may be able to<br class="">preserve source compatibility and avoid an error by implicitly<br class="">inserting a copy instead. This likely something we would only<br class="">do in a source-compatibility mode.<br class=""><br class="">Static enforcement will be used for:<br class=""><br class="">- immutable variables of all kinds,<br class=""><br class="">- local variables, except as affected by the use of closures<br class=""> (see below),<br class=""><br class="">- `inout` arguments, and<br class=""><br class="">- instance properties of value types.<br class=""><br class="">### Dynamic enforcement<br class=""><br class="">Under dynamic enforcement, the implementation will maintain<br class="">a record of whether each variable is currently being accessed.<br class="">If a conflict is detected, it will trigger a dynamic failure.<br class="">The compiler may emit an error statically if it detects that<br class="">dynamic enforcement will always detect a conflict.<br class=""><br class="">The bookkeeping requires two bits per variable, using a tri-state<br class="">of "unaccessed", "read", and "modified". Although multiple<br class="">simultaneous reads can be active at once, a full count can be<br class="">avoided by saving the old state across the access, with a little<br class="">cleverness.<br class=""><br class="">The bookkeeping is intended to be best-effort. It should reliably<br class="">detect deterministic violations. It is not required to detect<br class="">race conditions; it often will, and that's good, but it's not<br class="">required to. It *is* required to successfully handle the case<br class="">of concurrent reads without e.g. leaving the bookkeeping record<br class="">permanently in the "read" state. But it is acceptable for the<br class="">concurrent-reads case to e.g. leave the bookkeeping record in<br class="">the "unaccessed" case even if there are still active readers;<br class="">this permits the bookkeeping to use non-atomic operations.<br class="">However, atomic operations would have to be used if the bookkeeping<br class="">records were packed into a single byte for, say, different<br class="">properties of a class, because concurrent accesses are<br class="">allowed on different variables within a class.<br class=""><br class="">When the compiler detects that an access is "instantaneous",<br class="">in the sense that none of the code executed during the access<br class="">can possibly cause a re-entrant access to the same variable,<br class="">it can avoid updating the bookkeeping record and instead just<br class="">check that it has an appropriate value. This is common for<br class="">reads, which will often simply copy the value during the access.<br class="">When the compiler detects that all possible accesses are<br class="">instantaneous, e.g. if the variable is `private` or `internal`,<br class="">it can eliminate all bookkeeping. We expect this to be fairly<br class="">common.<br class=""><br class="">Dynamic enforcement will be used for:<br class=""><br class="">- local variables, when necessary due to the use of closures<br class=""> (see below),<br class=""><br class="">- instance properties of class types,<br class=""><br class="">- `static` and `class` properties, and<br class=""><br class="">- global variables.<br class=""><br class="">We should provide an attribute to allow dynamic enforcement<br class="">to be downgraded to undefined enforcement for a specific<br class="">property or class. It is likely that some clients will find<br class="">the performance consequences of dynamic enforcement to be<br class="">excessive, and it will be important to provide them an opt-out.<br class="">This will be especially true in the early days of the feature,<br class="">while we're still exploring implementation alternatives and<br class="">haven't yet implemented any holistic optimizations.<br class=""><br class="">Future work on isolating class instances may allow us to<br class="">use static enforcement for some class instance properties.<br class=""><br class="">### Undefined enforcement<br class=""><br class="">Undefined enforcement means that conflicts are not detected<br class="">either statically or dynamically, and instead simply have<br class="">undefined behavior. This is not a desireable mechanism<br class="">for ordinary code given Swift's "safe by default" design,<br class="">but it's the only real choice for things like unsafe pointers.<br class=""><br class="">Undefined enforcement will be used for:<br class=""><br class="">- the `memory` properties of unsafe pointers.<br class=""><br class="">### Enforcement for local variables captured by closures<br class=""><br class="">Our ability to statically enforce the Law of Exclusivity<br class="">relies on our ability to statically reason about where<br class="">uses occur. This analysis is usually straightforward for a<br class="">local variable, but it becomes complex when the variable is<br class="">captured in a closure because the control flow leading to<br class="">the use can be obscured. A closure can potentially be<br class="">executed re-entrantly or concurrently, even if it's known<br class="">not to escape. The following principles apply:<br class=""><br class="">- If a closure `C` potentially escapes, then for any variable<br class=""> `V` captured by `C`, all accesses to `V` potentially executed<br class=""> after a potential escape (including the accesses within `C`<br class=""> itself) must use dynamic enforcement unless all such acesses<br class=""> are reads.<br class=""><br class="">- If a closure `C` does not escape a function, then its<br class=""> use sites within the function are known; at each, the closure<br class=""> is either directly called or used as an argument to another<br class=""> call. Consider the set of non-escaping closures used at<br class=""> each such call. For each variable `V` captured by `C`, if<br class=""> any of those closures contains a write to `V`, all accesses<br class=""> within those closures must use dynamic enforcement, and<br class=""> the call is treated for purposes of static enforcement<br class=""> as if it were a write to `V`; otherwise, the accesses may use<br class=""> static enforcement, and the call is treated as if it were a<br class=""> read of `V`.<br class=""><br class="">It is likely that these rules can be improved upon over time.<br class="">For example, we should be able to improve on the rule for<br class="">direct calls to closures.<br class=""><br class="">## Explicit tools for ownership<br class=""><br class="">### Shared values<br class=""><br class="">A lot of the discussion in this section involves the new concept<br class="">of a *shared value*. As the name suggests, a shared value is a<br class="">value that has been shared with the current context by another<br class="">part of the program that owns it. To be consistent with the<br class="">Law of Exclusivity, because multiple parts of the program can<br class="">use the value at once, it must be read-only in all of them<br class="">(even the owning context). This concept allows programs to<br class="">abstract over values without copying them, just like `inout`<br class="">allows programs to abstract over variables.<br class=""><br class="">(Readers familiar with Rust will see many similarities between<br class="">shared values and Rust's concept of an immutable borrow.)<br class=""><br class="">When the source of a shared value is a storage reference, the<br class="">shared value acts essentially like an immutable reference<br class="">to that storage. The storage is accessed as a read for the<br class="">duration of the shared value, so the Law of Exclusivity<br class="">guarantees that no other accesses will be able to modify the<br class="">original variable during the access. Some kinds of shared<br class="">value may also bind to temporary values (i.e. an r-value).<br class="">Since temporary values are always owned by the current<br class="">execution context and used in one place, this poses no<br class="">additional semantic concerns.<br class=""><br class="">A shared value can be used in the scope that binds it<br class="">just like an ordinary parameter or `let` binding.<br class="">If the shared value is used in a place that requires<br class="">ownership, Swift will simply implicitly copy the value —<br class="">again, just like an ordinary parameter or `let` binding.<br class=""><br class="">#### Limitations of shared values<br class=""><br class="">This section of the document describes several ways to form<br class="">and use shared values. However, our current design does not<br class="">provide general, "first-class" mechanisms for working with them.<br class="">A program cannot return a shared value, construct an array<br class="">of shared values, store shared values into `struct` fields,<br class="">and so on. These limitations are similar to the existing<br class="">limitations on `inout` references. In fact, the similarities<br class="">are so common that it will be useful to have a term that<br class="">encompasses both: we will call them *ephemerals*.<br class=""><br class="">The fact that our design does not attempt to provide first-class<br class="">facilities for ephemerals is a well-considered decision,<br class="">born from a trio of concerns:<br class=""><br class="">- We have to scope this proposal to something that can<br class=""> conceivably be implemented in the coming months. We expect this<br class=""> proposal to yield major benefits to the language and its<br class=""> implementaton, but it is already quite broad and aggressive.<br class=""> First-class ephemerals would add enough complexity to the<br class=""> implementation and design that they are clearly out of scope.<br class=""> Furthermore, the remaining language-design questions are<br class=""> quite large; several existing languages have experimented<br class=""> with first-class ephemerals, and the results haven't been<br class=""> totally satisfactory.<br class=""><br class="">- Type systems trade complexity for expressivity.<br class=""> You can always accept more programs by making the type<br class=""> system more sophisticated, but that's not always a good<br class=""> trade-off. The lifetime-qualification systems behind<br class=""> first-class references in languages like Rust add a lot<br class=""> of complexity to the user model. That complexity has real<br class=""> costs for users. And it's still inevitably necessary<br class=""> to sometimes drop down to unsafe code to work around the<br class=""> limitations of the ownership system. Given that a line<br class=""> does have to drawn somewhere, it's not completely settled<br class=""> that lifetime-qualification systems deserve to be on the<br class=""> Swift side of the line.<br class=""><br class="">- A Rust-like lifetime system would not necessarily be<br class=""> as powerful in Swift as it is in Rust. Swift intentionally<br class=""> provides a language model which reserves a lot of<br class=""> implementation flexibility to both the authors of types<br class=""> and to the Swift compiler itself.<br class=""><br class=""> For example, polymorphic storage is quite a bit more<br class=""> flexible in Swift than it is in Rust. A<br class=""> `MutableCollection` in Swift is required to implement a<br class=""> `subscript` that provides accessor to an element for an index,<br class=""> but the implementation can satisfy this pretty much any way<br class=""> it wants. If generic code accesses this `subscript`, and it<br class=""> happens to be implemented in a way that provides direct access<br class=""> to the underlying memory, then the access will happen in-place;<br class=""> but if the `subscript` is implemented with a computed getter<br class=""> and setter, then the access will happen in a temporary<br class=""> variable and the getter and setter will be called as necessary.<br class=""> This only works because Swift's access model is highly<br class=""> lexical and maintains the ability to run arbitrary code<br class=""> at the end of an access. Imagine what it would take to<br class=""> implement a loop that added these temporary mutable<br class=""> references to an array — each iteration of the loop would<br class=""> have to be able to queue up arbitrary code to run as a clean-up<br class=""> when the function was finished with the array. This would<br class=""> hardly be a low-cost abstraction! A more Rust-like<br class=""> `MutableCollection` interface that worked within the<br class=""> lifetime rules would have to promise that the `subscript`<br class=""> returned a pointer to existing memory; and that wouldn't<br class=""> allow a computed implementation at all.<br class=""><br class=""> A similar problem arises even with simple `struct` members.<br class=""> The Rust lifetime rules say that, if you have a pointer to<br class=""> a `struct`, you can make a pointer to a field of that `struct`<br class=""> and it'll have the same lifetime as the original pointer.<br class=""> But this assumes not only that the field is actually stored<br class=""> in memory, but that it is stored *simply*, such that you can<br class=""> form a simple pointer to it and that pointer will obey the<br class=""> standard ABI for pointers to that type. This means that<br class=""> Rust cannot use layout optimizations like packing boolean<br class=""> fields together in a byte or even just decreasing the<br class=""> alignment of a field. This is not a guarantee that we are<br class=""> willing to make in Swift.<br class=""><br class="">For all of these reasons, while we remain theoretically<br class="">interested in exploring the possibilities of a more<br class="">sophisticated system that would allow broader uses of<br class="">ephemerals, we are not proposing to take that on now. Since<br class="">such a system would primarily consist of changes to the type<br class="">system, we are not concerned that this will cause ABI-stability<br class="">problems in the long term. Nor are we concerned that we will<br class="">suffer from source incompatibilities; we believe that any<br class="">enhancements here can be done as extensions and generalizations<br class="">of the proposed features.<br class=""><br class="">### Local ephemeral bindings<br class=""><br class="">It is already a somewhat silly limitation that Swift provides<br class="">no way to abstract over storage besides passing it as an<br class="">`inout` argument. It's an easy limitation to work around,<br class="">since programmers who want a local `inout` binding can simply<br class="">introduce a closure and immediately call it, but that's an<br class="">awkward way of achieving something that ought to be fairly easy.<br class=""><br class="">Shared values make this limitation even more apparent, because<br class="">a local shared value is an interesting alternative to a local `let`:<br class="">it avoids a copy at the cost of preventing other accesses to<br class="">the original storage. We would not encourage programmers to<br class="">use `shared` instead of `let` throughout their code, especially<br class="">because the optimizer will often be able to eliminate the copy<br class="">anyway. However, the optimizer cannot always remove the copy,<br class="">and so the `shared` micro-optimization can be useful in select<br class="">cases. Furthermore, eliminating the formal copy may also be<br class="">semantically necessary when working with non-copyable types.<br class=""><br class="">We propose to remove this limitation in a straightforward way:<br class=""><br class="">```<br class=""> inout root = &tree.root<br class=""><br class=""> shared elements = self.queue<br class="">```<br class=""><br class="">The initializer is required and must be a storage reference<br class="">expression. The access lasts for the remainder of the scope.<br class=""><br class="">### Function parameters<br class=""><br class="">Function parameters are the most important way in which<br class="">programs abstract over values. Swift currently provides<br class="">three kinds of argument-passing:<br class=""><br class="">- Pass-by-value, owned. This is the rule for ordinary<br class=""> arguments. There is no way to spell this explicitly.<br class=""><br class="">- Pass-by-value, shared. This is the rule for the `self`<br class=""> arguments of `nonmutating` methods. There is no way to<br class=""> spell this explicitly.<br class=""><br class="">- Pass-by-reference. This is the rule used for `inout`<br class=""> arguments and the `self` arguments of `mutating` methods.<br class=""><br class="">Our proposal here is just to allow the non-standard<br class="">cases to be spelled explicitly:<br class=""><br class="">- A function argument can be explicitly declared `owned`:<br class=""><br class=""> ```<br class=""> func append(_ values: owned [Element]) {<br class=""> ...<br class=""> }<br class=""> ```<br class=""><br class=""> This cannot be combined with `shared` or `inout`.<br class=""><br class=""> This is just an explicit way of writing the default, and<br class=""> we do not expect that users will write it often unless<br class=""> they're working with non-copyable types.<br class=""><br class="">- A function argument can be explicitly declared `shared`.<br class=""><br class=""> ```<br class=""> func ==(left: shared String, right: shared String) -> Bool {<br class=""> ...<br class=""> }<br class=""> ```<br class=""><br class=""> This cannot be combined with `owned` or `inout`.<br class=""><br class=""> If the function argument is a storage reference expression,<br class=""> that storage is accessed as a read for the duration of the<br class=""> call. Otherwise, the argument expression is evaluated as<br class=""> an r-value and that temporary value is shared for the call.<br class=""> It's important to allow temporary values to be shared for<br class=""> function arguments because many function parameters will be<br class=""> marked as `shared` simply because the functions don't<br class=""> actually from owning that parameter, not because it's in<br class=""> any way semantically important that they be passed a<br class=""> reference to an existing variable. For example, we expect<br class=""> to change things like comparison operators to take their<br class=""> parameters `shared`, because it needs to be possible to<br class=""> compare non-copyable values without claiming them, but<br class=""> this should not prevent programmers from comparing things<br class=""> to literal values.<br class=""><br class=""> Like `inout`, this is part of the function type. Unlike<br class=""> `inout`, most function compatibility checks (such as override<br class=""> and function conversion checking) should succeed with a<br class=""> `shared` / `owned` mismatch. If a function with an `owned`<br class=""> parameter is converted to (or overrides) a function with a<br class=""> `shared` parameter, the argument type must actually be<br class=""> copyable.<br class=""><br class="">- A method can be explicitly declared `consuming`.<br class=""><br class=""> ```<br class=""> consuming func moveElements(into collection: inout [Element]) {<br class=""> ...<br class=""> }<br class=""> ```<br class=""><br class=""> This causes `self` to be passed as an owned value and therefore<br class=""> cannot be combined with `mutating` or `nonmutating`.<br class=""><br class=""> `self` is still an immutable binding within the method.<br class=""><br class="">### Function results<br class=""><br class="">As discussed at the start of this section, Swift's lexical<br class="">access model does not extend well to allowing ephemerals<br class="">to be returned from functions. Performing an access requires<br class="">executing storage-specific code at both the beginning and<br class="">the end of the access. After a function returns, it has no<br class="">further ability to execute code.<br class=""><br class="">We could, conceivably, return a callback along with the<br class="">ephemeral, with the expectation that the callback will be<br class="">executed when the caller is done with the ephemeral.<br class="">However, this alone would not be enough, because the callee<br class="">might be relying on guarantees from its caller. For example,<br class="">considering a `mutating` method on a `struct` which wants<br class="">to returns an `inout` reference to a stored property. The<br class="">correctness of this depends not only on the method being able<br class="">to clean up after the access to the property, but on the<br class="">continued validity of the variable to which `self` was bound.<br class="">What we really want is to maintain the current context in the<br class="">callee, along with all the active scopes in the caller, and<br class="">simply enter a new nested scope in the caller with the<br class="">ephemeral as a sort of argument. But this is a well-understood<br class="">situation in programming languages: it is just a kind of<br class="">co-routine. (Because of the scoping restrictions, it can<br class="">also be thought of as sugar for a callback function in<br class="">which `return`, `break`, etc. actually work as expected.)<br class=""><br class="">In fact, co-routines are useful for solving a number of<br class="">problems relating to ephemerals. We will explore this<br class="">idea in the next few sub-sections.<br class=""><br class="">### `for` loops<br class=""><br class="">In the same sense that there are three interesting ways of<br class="">passing an argument, we can identify three interesting styles<br class="">of iterating over a sequence. Each of these can be expressed<br class="">with a `for` loop.<br class=""><br class="">#### Consuming iteration<br class=""><br class="">The first iteration style is what we're already familiar with<br class="">in Swift: a consuming iteration, where each step is presented<br class="">with an owned value. This is the only way we can iterate over<br class="">an arbitrary sequence where the values might be created on demand.<br class="">It is also important for working with collections of non-copyable<br class="">types because it allows the collection to be destructured and the<br class="">loop to take ownership of the elements. Because it takes ownership<br class="">of the values produced by a sequence, and because an arbitrary<br class="">sequence cannot be iterated multiple times, this is a<br class="">`consuming` operation on `Sequence`.<br class=""><br class="">This can be explicitly requested by declaring the iteration<br class="">variable `owned`:<br class=""><br class="">```<br class=""> for owned employee in company.employees {<br class=""> newCompany.employees.append(employee)<br class=""> }<br class="">```<br class=""><br class="">It is also used implicitly when the requirements for a<br class="">non-mutating iteration are not met. (Among other things,<br class="">this is necessary for source compatibility.)<br class=""><br class="">The next two styles make sense only for collections.<br class=""><br class="">#### Non-mutating iteration<br class=""><br class="">A non-mutating iteration simply visits each of the elements<br class="">in the collection, leaving it intact and unmodified. We have<br class="">no reason to copy the elements; the iteration variable can<br class="">simply be bound to a shared value. This is a `nonmutating`<br class="">operaton on `Collection`.<br class=""><br class="">This can be explicitly requested by declaring the iteration<br class="">variable `shared`:<br class=""><br class="">```<br class=""> for shared employee in company.employees {<br class=""> if !employee.respected { throw CatastrophicHRFailure() }<br class=""> }<br class="">```<br class=""><br class="">It is also used by default when the sequence type is known to<br class="">conform to `Collection`, since this is the optimal way of<br class="">iterating over a collection.<br class=""><br class="">```<br class=""> for employee in company.employees {<br class=""> if !employee.respected { throw CatastrophicHRFailure() }<br class=""> }<br class="">```<br class=""><br class="">If the sequence operand is a storage reference expression,<br class="">the storage is accessed for the duration of the loop. Note<br class="">that this means that the Law of Exclusivity will implicitly<br class="">prevent the collection from being modified during the<br class="">iteration. Programs can explicitly request an iteration<br class="">over a copy of the value in that storage by using the `copy`<br class="">intrinsic function on the operand.<br class=""><br class="">#### Mutating iteration<br class=""><br class="">A mutating iteration visits each of the elements and<br class="">potentially changes it. The iteration variable is an<br class="">`inout` reference to the element. This is a `mutating`<br class="">operation on `MutableCollection`.<br class=""><br class="">This must be explicitly requested by declaring the<br class="">iteration variable `inout`:<br class=""><br class="">```<br class=""> for inout employee in company.employees {<br class=""> employee.respected = true<br class=""> }<br class="">```<br class=""><br class="">The sequence operand must be a storage reference expression.<br class="">The storage will be accessed for the duraton of the loop,<br class="">which (as above) will prevent any other overlapping accesses<br class="">to the collection. (But this rule does not apply if the<br class="">collection type defines the operation as a non-mutating<br class="">operation, which e.g. a reference-semantics collection might.)<br class=""><br class="">#### Expressing mutating and non-mutating iteration<br class=""><br class="">Mutating and non-mutating iteration require the collection<br class="">to produce ephemeral values at each step. There are several<br class="">ways we could express this in the language, but one reasonable<br class="">approach would be to use co-routines. Since a co-routine does<br class="">not abandon its execution context when yielding a value to its<br class="">caller, it is reasonable to allow a co-routine to yield<br class="">multiple times, which corresponds very well to the basic<br class="">code pattern of a loop. This produces a kind of co-routine<br class="">often called a generator, which is used in several major<br class="">languages to conveniently implement iteration. In Swift,<br class="">to follow this pattern, we would need to allow the definition<br class="">of generator functions, e.g.:<br class=""><br class="">```<br class=""> mutating generator iterateMutable() -> inout Element {<br class=""> var i = startIndex, e = endIndex<br class=""> while i != e {<br class=""> yield &self[i]<br class=""> self.formIndex(after: &i)<br class=""> }<br class=""> }<br class="">```<br class=""><br class="">On the client side, it is clear how this could be used to<br class="">implement `for` loops; what is less clear is the right way to<br class="">allow generators to be used directly by code. There are<br class="">interesting constraints on how the co-routine can be used<br class="">here because, as mentioned above, the entire co-routine<br class="">must logically execute within the scope of an access to the<br class="">base value. If, as is common for generators, the generator<br class="">function actually returns some sort of generator object,<br class="">the compiler must ensure that that object does not escape<br class="">that enclosing access. This is a significant source of<br class="">complexity.<br class=""><br class="">### Generalized accessors<br class=""><br class="">Swift today provides very coarse tools for implementing<br class="">properties and subscripts: essentially, just `get` and `set`<br class="">methods. These tools are inadequate for tasks where<br class="">performance is critical because they don't allow direct<br class="">access to values without copies. The standard library<br class="">has access to a slightly broader set of tools which can<br class="">provide such direct access in limited cases, but they're<br class="">still quite weak, and we've been reluctant to expose them to<br class="">users for a variety of reasons.<br class=""><br class="">Ownership offers us an opportunity to revisit this problem<br class="">because `get` doesn't work for collections of non-copyable<br class="">types because it returns a value, which must therefore be<br class="">owned. The accessor really needs to be able to yield a<br class="">shared value instead of returning an owned one. Again,<br class="">one reasonable approach for allowing this is to use a<br class="">special kind of co-routine. Unlike a generator, this<br class="">co-routine would be required to yield exactly once.<br class="">And there is no need to design an explicit way for programmers<br class="">to invoke one because these would only be used in accessors.<br class=""><br class="">The idea is that, instead of defining `get` and `set`,<br class="">a storage declaration could define `read` and `modify`:<br class=""><br class="">```<br class=""> var x: String<br class=""> var y: String<br class=""> var first: String {<br class=""> read {<br class=""> if x < y { yield x }<br class=""> else { yield y }<br class=""> }<br class=""> modify {<br class=""> if x < y { yield &x }<br class=""> else { yield &y }<br class=""> }<br class=""> }<br class="">```<br class=""><br class="">A storage declaration must define either a `get` or a `read`<br class="">(or be a stored property), but not both.<br class=""><br class="">To be mutable, a storage declaration must also define either a<br class="">`set` or a `modify`. It may also choose to define *both*, in<br class="">which case `set` will be used for assignments and `modify` will<br class="">be used for modifications. This is useful for optimizing<br class="">certain complex computed properties because it allows modifications<br class="">to be done in-place without forcing simple assignments to first<br class="">read the old value; however, care must be taken to ensure that<br class="">the `modify` is consistent in behavior with the `get` and the<br class="">`set`.<br class=""><br class="">### Intrinsic functions<br class=""><br class="">#### `move`<br class=""><br class="">The Swift optimizer will generally try to move values around<br class="">instead of copying them, but it can be useful to force its hand.<br class="">For this reason, we propose the `move` function. Conceptually,<br class="">`move` is simply a top-level function in the Swift standard<br class="">library:<br class=""><br class="">```<br class=""> func move<T>(_ value: T) -> T {<br class=""> return value<br class=""> }<br class="">```<br class=""><br class="">However, it is blessed with some special semantics. It cannot<br class="">be used indirectly. The argument expression must be a reference<br class="">to some kind of local owning storage: either a `let`, a `var`,<br class="">or an `inout` binding. A call to `move` is evaluated by<br class="">semantically moving the current value out of the argument<br class="">variable and returning it as the type of the expression,<br class="">leaving the variable uninitialized for the purposes of the<br class="">definitive-initialization analysis. What happens with the<br class="">variable next depends on the kind of variable:<br class=""><br class="">- A `var` simply transitions back to being uninitialized.<br class=""> Uses of it are illegal until it is assigned a new value and<br class=""> thus reinitialized.<br class=""><br class="">- An `inout` binding is just like a `var`, except that it is<br class=""> illegal for it to go out of scope uninitialized. That is,<br class=""> if a program moves out of an `inout` binding, the program<br class=""> must assign a new value to it before it can exit the scope<br class=""> in any way (including by throwing an error). Note that the<br class=""> safety of leaving an `inout` temporarily uninitialized<br class=""> depends on the Law of Exclusivity.<br class=""><br class="">- A `let` cannot be reinitialized and so cannot be used<br class=""> again at all.<br class=""><br class="">This should be a straightforward addition to the existing<br class="">definitive-initialization analysis, which proves that local<br class="">variables are initialized before use.<br class=""><br class="">#### `copy`<br class=""><br class="">`copy` is a top-level function in the Swift standard library:<br class=""><br class="">```<br class=""> func copy<T>(_ value: T) -> T {<br class=""> return value<br class=""> }<br class="">```<br class=""><br class="">The argument must be a storage reference expression. The<br class="">semantics are exactly as given in the above code: the argument<br class="">value is returned. This is useful for several reasons:<br class=""><br class="">- It suppresses syntactic special-casing. For example, as<br class=""> discussed above, if a `shared` argument is a storage<br class=""> reference, that storage is normally accessed for the duration<br class=""> of the call. The programmer can suppress this and force the<br class=""> copy to complete before the call by calling `copy` on the<br class=""> storage reference before <br class=""><br class="">- It is necessary for types that have suppressed implicit<br class=""> copies. See the section below on non-copyable types.<br class=""><br class="">#### `endScope`<br class=""><br class="">`endScope` is a top-level function in the Swift standard library:<br class=""><br class="">```<br class=""> func endScope<T>(_ value: T) -> () {}<br class="">```<br class=""><br class="">The argument must be a reference to a local `let`, `var`, or<br class="">standalone (non-parameter, non-loop) `inout` or `shared`<br class="">declaration. If it's a `let` or `var`, the variable is<br class="">immediately destroyed. If it's an `inout` or `shared`,<br class="">the access immediately ends.<br class=""><br class="">The definitive-initialization analysis must prove that<br class="">the declaration is not used after this call. It's an error<br class="">if the storage is a `var` that's been captured in an escaping<br class="">closure.<br class=""><br class="">This is useful for ending an access before control reaches the<br class="">end of a scope, as well as for micro-optimizing the destruction<br class="">of values.<br class=""><br class="">`endScope` provides a guarantee that the given variable has<br class="">been destroyed, or the given access has ended, by the time<br class="">of the execution of the call. It does not promise that these<br class="">things happen exactly at that point: the implementation is<br class="">still free to end them earlier.<br class=""><br class="">### Lenses<br class=""><br class="">Currently, all storage reference expressions in Swift are *concrete*:<br class="">every component is statically resolvable to a storage declaration.<br class="">There is some recurring interest in the community in allowing programs<br class="">to abstract over storage, so that you might say:<br class=""><br class="">```<br class=""> let prop = Widget.weight<br class="">```<br class=""><br class="">and then `prop` would be an abstract reference to the `weight`<br class="">property, and its type would be something like `(Widget) -> Double`.<br class=""><br class="">This feature is relevant to the ownership model because an ordinary<br class="">function result must be an owned value: not shared, and not mutable.<br class="">This means lenses could only be used to abstract *reads*, not<br class="">*writes*, and could only be created for copyable properties. It<br class="">also means code using lenses would involve more copies than the<br class="">equivalent code using concrete storage references.<br class=""><br class="">Suppose that, instead of being simple functions, lenses were their<br class="">own type of value. An application of a lens would be a storage<br class="">reference expression, but an *abstract* one which accessed<br class="">statically-unknown members. This would require the language<br class="">implementation to be able to perform that sort of access<br class="">dynamically. However, the problem of accessing an unknown<br class="">property is very much like the problem of accessing a known<br class="">property whose implementation is unknown; that is, the language<br class="">already has to do very similar things in order to implement<br class="">generics and resilience.<br class=""><br class="">Overall, such a feature would fit in very neatly with the<br class="">ownership model laid out here.<br class=""><br class="">## Non-copyable types<br class=""><br class="">Non-copyable types are useful in a variety of expert situations.<br class="">For example, they can be used to efficiently express unique<br class="">ownership. They are also interesting for expressing values<br class="">that have some sort of independent identity, such as atomic<br class="">types. They can also be used as a formal mechanism for<br class="">encouraging code to work more efficiently with types that<br class="">might be expensive to copy, such as large struct types. The<br class="">unifying theme is that we do not want to allow the type to<br class="">be copied implicitly.<br class=""><br class="">The complexity of handling non-copyable types in Swift<br class="">comes from two main sources:<br class=""><br class="">- The language must provide tools for moving values around<br class=""> and sharing them without forcing copies. We've already<br class=""> proposed these tools in this document because they're<br class=""> equally important for optimizing the use of copyable types.<br class=""><br class="">- The generics system has to be able to express generics over<br class=""> non-copyable types without massively breaking source<br class=""> compatibility and forcing non-copyable types on everybody.<br class=""><br class="">Otherwise, the feature itself is pretty small. The compiler<br class="">implicitly emits moves instead of copies, just like we discussed<br class="">above for the `move` intrinsic, and then diagnoses anything<br class="">that that didn't work for.<br class=""><br class="">### `moveonly` contexts<br class=""><br class="">The generics problem is real, though. The most obvious way<br class="">to model copyability in Swift is to have a `Copyable`<br class="">protocol which types can conform to. An unconstrained type<br class="">parameter `T` would then not be assumed to be copyable.<br class="">Unfortunately, this would be a disaster for both source<br class="">compatibility and usability, because almost all the existing<br class="">generic code written in Swift assumes copyability, and<br class="">we really don't want programmers to have to worry about<br class="">non-copyable types in their first introduction to generic<br class="">code.<br class=""><br class="">Furthermore, we don't want types to have to explicitly<br class="">declare conformance to `Copyable`. That should be the<br class="">default.<br class=""><br class="">The logical solution is to maintain the default assumption<br class="">that all types are copyable, and then allow select contexts<br class="">to turn that assumption off. We will cause these contexts<br class="">`moveonly` contexts. All contexts lexically nested within<br class="">a `moveonly` context are also implicitly `moveonly`.<br class=""><br class="">A type can be a `moveonly` context:<br class=""><br class="">```<br class=""> moveonly struct Array<Element> {<br class=""> // Element and Array<Element> are not assumed to be copyable here<br class=""> }<br class="">```<br class=""><br class="">This suppresses the `Copyable` assumption for the type<br class="">declared, its generic arguments (if any), and their<br class="">hierarchies of associated types.<br class=""><br class="">An extension can be a `moveonly` context:<br class=""><br class="">```<br class=""> moveonly extension Array {<br class=""> // Element and Array<Element> are not assumed to be copyable here<br class=""> }<br class="">```<br class=""><br class="">A type can declare conditional copyability using a conditional<br class="">conformance:<br class=""><br class="">```<br class=""> moveonly extension Array: Copyable where Element: Copyable {<br class=""> ...<br class=""> }<br class="">```<br class=""><br class="">Conformance to `Copyable`, conditional or not, is an<br class="">inherent property of a type and must be declared in the<br class="">same module that defines the type. (Or possibly even the<br class="">same file.)<br class=""><br class="">A non-`moveonly` extension of a type reintroduces the<br class="">copyability assumption for the type and its generic<br class="">arguments. This is necessary in order to allow standard<br class="">library types to support non-copyable elements without<br class="">breaking compatibility with existing extensions. If the<br class="">type doesn't declare any conformance to `Copyable`, giving<br class="">it a non-`moveonly` extension is an error.<br class=""><br class="">A function can be a `moveonly` context:<br class=""><br class="">```<br class=""> extension Array {<br class=""> moveonly func report<U>(_ u: U)<br class=""> }<br class="">```<br class=""><br class="">This suppresses the copyability assumption for any new<br class="">generic arguments and their hierarchies of associated types.<br class=""><br class="">A lot of the details of `moveonly` contexts are still up<br class="">in the air. It is likely that we will need substantial<br class="">implementation experience before we can really settle on<br class="">the right design here.<br class=""><br class="">One possibility we're considering is that `moveonly`<br class="">contexts will also suppress the implicit copyability<br class="">assumption for values of copyable types. This would<br class="">provide an important optimization tool for code that<br class="">needs to be very careful about copies.<br class=""><br class="">### `deinit` for non-copyable types<br class=""><br class="">A value type declared `moveonly` which does not conform<br class="">to `Copyable` (even conditionally) may define a `deinit`<br class="">method. `deinit` must be defined in the primary type<br class="">definition, not an extension.<br class=""><br class="">`deinit` will be called to destroy the value when it is<br class="">no longer required. This permits non-copyable types to be<br class="">used to express the unique ownership of resources. For<br class="">example, here is a simple file-handle type that ensures<br class="">that the handle is closed when the value is destroyed:<br class=""><br class="">```<br class=""> moveonly struct File {<br class=""> var descriptor: Int32<br class=""><br class=""> init(filename: String) throws {<br class=""> descriptor = Darwin.open(filename, O_RDONLY)<br class=""><br class=""> // Abnormally exiting 'init' at any point prevents deinit<br class=""> // from being called.<br class=""> if descriptor == -1 { throw ... }<br class=""> }<br class=""><br class=""> deinit {<br class=""> _ = Darwin.close(descriptor)<br class=""> }<br class=""><br class=""> consuming func close() throws {<br class=""> if Darwin.fsync(descriptor) != 0 { throw ... }<br class=""><br class=""> // This is a consuming function, so it has ownership of self.<br class=""> // It doesn't consume self in any other way, so it will<br class=""> // destroy it when it exits by calling deinit. deinit<br class=""> // will then handle actually closing the descriptor.<br class=""> }<br class=""> }<br class="">```<br class=""><br class="">Swift is permitted to destroy a value (and thus call `deinit`)<br class="">at any time between its last use and its formal point of<br class="">destruction. The exact definition of "use" for the purposes<br class="">of this definition is not yet fully decided.<br class=""><br class="">If the value type is a `struct`, `self` can only be used<br class="">in `deinit` in order to refer to the stored properties<br class="">of the type. The stored properties of `self` are treated<br class="">like local `let` constants for the purposes of the<br class="">definitive-initialization analysis; that is, they are owned<br class="">by the `deinit` and can be moved out of.<br class=""><br class="">If the value type is an `enum`, `self` can only be used<br class="">in `deinit` as the operand of a `switch`. Within this<br class="">`switch`, any associated values are used to initialize<br class="">the corresponding bindings, which take ownership of those<br class="">values. Such a `switch` leaves `self` uninitialized.<br class=""><br class="">### Explicitly-copyable types<br class=""><br class="">Another idea in the area of non-copyable types that we're<br class="">exploring is the ability to declare that a type cannot<br class="">be implicitly copied. For example, a very large struct<br class="">can formally be copied, but it might be an outsized<br class="">impact on performance if it is copied unnecessarily.<br class="">Such a type should conform to `Copyable`, and it should<br class="">be possible to request a copy with the `copy` function,<br class="">but the compiler should diagnose any implicit copies<br class="">the same way that it would diagnose copies of a<br class="">non-copyable type.<br class=""><br class="">## Implementation priorities<br class=""><br class="">This document has laid out a large amount of work.<br class="">We can summarize it as follows:<br class=""><br class="">- Enforcing the Law of Exclusivity:<br class=""><br class=""> - Static enforcement<br class=""> - Dynamic enforcement<br class=""> - Optimization of dynamic enforcement<br class=""><br class="">- New annotations and declarations:<br class=""><br class=""> - `shared` parameters<br class=""> - `consuming` methods<br class=""> - Local `shared` and `inout` declarations<br class=""><br class="">- New intrinsics affecting DI:<br class=""><br class=""> - The `move` function and its DI implications<br class=""> - The `endScope` function and its DI implications<br class=""><br class="">- Co-routine features:<br class=""><br class=""> - Generalized accessors<br class=""> - Generators<br class=""><br class="">- Non-copyable types<br class=""><br class=""> - Further design work<br class=""> - DI enforcement<br class=""> - `moveonly` contexts<br class=""><br class="">The single most important goal for the upcoming releases is<br class="">ABI stability. The prioritization and analysis of these<br class="">features must center around their impact on the ABI. With<br class="">that in mind, here are the primary ABI considerations:<br class=""><br class="">The Law of Exclusivity affects the ABI because it<br class="">changes the guarantees made for parameters. We must adopt<br class="">this rule before locking down on the ABI, or else we will<br class="">get stuck making conservative assumptions forever.<br class="">However, the details of how it is enforced do not affect<br class="">the ABI unless we choose to offload some of the work to the<br class="">runtime, which is not necessary and which can be changed<br class="">in future releases. (As a technical note, the Law<br class="">of Exclusivity is likely to have a major impact on the<br class="">optimizer; but this is an ordinary project-scheduling<br class="">consideration, not an ABI-affecting one.)<br class=""><br class="">The standard library is likely to enthusiastically adopt<br class="">ownership annotations on parameters. Those annotations will<br class="">affect the ABI of those library routines. Library<br class="">developers will need time in order to do this adoption,<br class="">but more importantly, they will need some way to validate<br class="">that their annotations are useful. Unfortunately, the best<br class="">way to do that validation is to implement non-copyable types,<br class="">which are otherwise very low on the priority list.<br class=""><br class="">The generalized accessors work includes changing the standard<br class="">set of "most general" accessors for properties and subscripts<br class="">from `get`/`set`/`materializeForSet` to (essentially)<br class="">`read`/`set`/`modify`. This affects the basic ABI of<br class="">all polymorphic property and subscript accesses, so it<br class="">needs to happen. However, this ABI change can be done<br class="">without actually taking the step of allowing co-routine-style<br class="">accessors to be defined in Swift. The important step is<br class="">just ensuring that the ABI we've settled on is good<br class="">enough for co-routines in the future.<br class=""><br class="">The generators work may involve changing the core collections<br class="">protocols. That will certainly affect the ABI. In contrast<br class="">with the generalized accessors, we will absolutely need<br class="">to implement generators in order to carry this out.<br class=""><br class="">Non-copyable types and algorithms only affect the ABI<br class="">inasmuch as they are adopted in the standard library.<br class="">If the library is going to extensively adopt them for<br class="">standard collections, that needs to happen before we<br class="">stabilize the ABI.<br class=""><br class="">The new local declarations and intrinsics do not affect the ABI.<br class="">(As is often the case, the work with the fewest implications<br class="">is also some of the easiest.)<br class=""><br class="">Adopting ownership and non-copyable types in the standard<br class="">library is likely to be a lot of work, but will be important<br class="">for the usability of non-copyable types. It would be very<br class="">limiting if it was not possible to create an `Array`<br class="">of non-copyable types.<br class=""><br class="">(end)<br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></blockquote><br class=""></div></div></blockquote></div><br class=""></body></html>