[Manifesto] Ownership

Hi John,

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.

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.

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.

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.

OK. You got me convinced this is probably the most consistent approach. Do you envision any other policy protocol?

Not right away, but it's possible that eventually we might want equivalents to some of the other magic protocols in Rust, like Send (which IIRC promises that shared references are thread-safe; that's a similar sort of fundamental property).

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?

Well, for one, CPUs may get cleverer here over time. So I would be uncomfortable with cementing this too much in the language.

I don't think this will dramatically improve over time. Moreover, spatial/physical dependencies may not be specific to cache lines. Another example would be two boolean packed into two bits. Those variables are not independent because writing into one of them requires loading and writing both of them (unless you exclusively use atomic operations).

Correct. This design doesn't *completely* give up on allowing bit-packing in classes, but it does make it much harder. That was considered. :)

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.

This indeed wouldn't be statically checkable, but this could be (maybe as an opt-in?) dynamically checked.

Yes, we could certainly do layout dynamically based on the actual cache-line size. But I hope we can agree that putting every class property on its own cache line by default is not actually acceptable. :)

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.

Allowing some sort of intelligent layout to prevent cache-line collisions would certainly be a secondary goal of a concurrency design, though.

OK

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.

struct Ressource {
  /* content is unimportant here */
}

class Worker {
  shared ressource: Ressource

  init(ressource: shared Ressource) {
      self.ressource = ressource
  }

  /* ... */
}

let ressource = Ressource()

for i in 0..<10 {
 let worker = Worker(ressource: ressource)
 worker.schedule()
}
waitAllWorkers()

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?

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.

There may be dynamic approaches that could work. What we want is make sure that no dangling ephemeral remains after the end of life of the pointed ressource. We could imagine a solution based on weak-reference wherever we cannot statically enforce the lifetime rules. In that case, all references to the shared ressource, or all references to objects containing the ephemeral might be enforced to be weak and nil-ified when the value reaches its end of life. I'm aware there is a lot of issues with that idea. The first issue is that another thread may have a strong reference on the Worker because it is running a method of Worker when the Ressource becomes unavailable, which just breaks everything). Another issue is the runtime overhead of the bookkeeping requested to maintain the list of references associated to Ressource.

Actually, it would probably be better to forget that idea :)

Well, you could allocate a refcounted object to do the bookkeeping and then implicitly capture that along with the shared value. That would be quite the perf hit, though.

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?

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.

OK

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.

[1] [swift-evolution] Proposal to improve C pointer type import

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.

Sorry about this. My whole point is simply: how can we make interaction with C safer in order to make it easier to migrate from C to Swift without rewriting everything from scratch. I had no idea you were working on the ownership principles at the time and it clearly looks like a big step toward that goal.

Yeah, I definitely think this has to happen first.

John.

···

On Feb 20, 2017, at 4:55 PM, Florent Bruneau <florent.bruneau@intersec.com> wrote:

Le 20 févr. 2017 à 18:22, John McCall <rjmccall@apple.com> a écrit :

On Feb 20, 2017, at 3:40 AM, Florent Bruneau <florent.bruneau@intersec.com> wrote:

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.

Thx.

Le 17 févr. 2017 à 09:25, John McCall via swift-evolution <swift-evolution@swift.org> a écrit :

Hello, swift-evolution.

Memory ownership is a topic that keeps poking its head up here. Core team
members have mentioned several times that it's something we're interested in
working on. Questions sometimes get referred back to it, saying stuff like
"we're working on tools to let you control ARC a little better". It's even on the
short list of high-priority features for Swift 4:

GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.

Memory ownership model: an (opt-in) Cyclone/Rust-inspired memory
ownership model is highly desired by systems programmers and for other
high-performance applications that want predictable and deterministic
performance. This feature will fundamentally shape the ABI, from low-level
language concerns such as "inout" and low-level "addressors" to its impact
on the standard library. While a full memory ownership model is likely too
large for Swift 4 stage 1, we need a comprehensive design to understand
how it will change the ABI.

But that's all pretty vague. What is ownership? What does it mean for
programmers? Is somebody ever going to actually write that comprehensive
design that was supposed to come out during Stage 1?

Well, here you go.

I want to emphasize that this document is two things. It is a *manifesto*,
because it describes the whole problem and presents a holistic solution to it.
And it is a *meta-proposal*, because that holistic solution imagines and a number
of changes, each of which is worthy of a proposal; it is, essentially, a proposal
that we write a bunch of smaller proposals for each of these changes. But it's
not actually a concrete proposal for those smaller changes: it's often lacking in
that level of detail, and it leaves a number of questions open. This document, itself,
will not undergo the formal evolution process. And it may be that some of these
changes aren't really necessary, or that they need major reconsideration before
they're appropriate for proposal. But our hope — my hope — is that this
document is sufficient for you to understand the holistic approach we're suggesting,
or at least puts you in a position where you're comfortable asking questions
and trying to figure it out.

So, like I said, this isn't a formal proposal. What, then, are we hoping to achieve?
Well, we want people to talk about it. We'd like to achieve a consensus about
whether this basic approach makes sense for the language and achieves its goals.
And, assuming that the consensus is "yes" and that we should go forward with it,
we'd like this document — and this thread — to serve as an introduction to the
topic that we can refer back to when we're proposing and discussing all of those
changes in the weeks to come.

With that said, let's get started.

John.

------------------------------------------------------------------

# Ownership

## Introduction

Adding "ownership" to Swift is a major feature with many benefits
for programmers. This document is both a "manifesto" and a
"meta-proposal" for ownership: it lays out the basic goals of
the work, describes a general approach for achieving those goals,
and proposes a number of specific changes and features, each of
which will need to be separately discussed in a smaller and more
targeted proposal. This document is intended to provide a framework
for understanding the contributions of each of those changes.

### Problem statement

The widespread use of copy-on-write value types in Swift has generally
been a success. It does, however, come with some drawbacks:

* Reference counting and uniqueness testing do impose some overhead.

* Reference counting provides deterministic performance in most cases,
but that performance can still be complex to analyze and predict.

* The ability to copy a value at any time and thus "escape" it forces
the underlying buffers to generally be heap-allocated. Stack allocation
is far more efficient but does require some ability to prevent, or at
least recognize, attempts to escape the value.

Certain kinds of low-level programming require stricter performance
guarantees. Often these guarantees are less about absolute performance
than *predictable* performance. For example, keeping up with an audio
stream is not a taxing job for a modern processor, even with significant
per-sample overheads, but any sort of unexpected hiccup is immediately
noticeable by users.

Another common programming task is to optimize existing code when something
about it falls short of a performance target. Often this means finding
"hot spots" in execution time or memory use and trying to fix them in some
way. When those hot spots are due to implicit copies, Swift's current
tools for fixing the problem are relatively poor; for example, a programmer
can fall back on using unsafe pointers, but this loses a lot of the
safety benefits and expressivity advantages of the library collection types.

We believe that these problems can be addressed with an opt-in set of
features that we collectively call *ownership*.

### What is ownership?

*Ownership* is the responsibility of some piece of code to
eventually cause a value to be destroyed. An *ownership system*
is a set of rules or conventions for managing and transferring
ownership.

Any language with a concept of destruction has a concept of
ownership. In some languages, like C and non-ARC Objective-C,
ownership is managed explicitly by programmers. In other
languages, like C++ (in part), ownership is managed by the
language. Even languages with implicit memory management still
have libraries with concepts of ownership, because there are
other program resources besides memory, and it is important
to understand what code has the responsibility to release
those resources.

Swift already has an ownership system, but it's "under the covers":
it's an implementation detail that programmers have little
ability to influence. What we are proposing here is easy
to summarize:

- We should add a core rule to the ownership system, called
the Law of Exclusivity, which requires the implementation
to prevent variables from being simultaneously accessed
in conflicting ways. (For example, being passed `inout`
to two different functions.) This will not be an opt-in
change, but we believe that most programs will not be
adversely affected.

- We should add features to give programmers more control over
the ownership system, chiefly by allowing the propagation
of "shared" values. This will be an opt-in change; it
will largely consist of annotations and language features
which programmers can simply not use.

- We should add features to allow programmers to express
types with unique ownership, which is to say, types that
cannot be implicitly copied. This will be an opt-in
feature intended for experienced programmers who desire
this level of control; we do not intend for ordinary
Swift programming to require working with such types.

These three tentpoles together have the effect of raising
the ownership system from an implementation detail to a more
visible aspect of the language. They are also somewhat
inseparable, for reasons we'll explain, although of course they
can be prioritized differently. For these reasons, we will
talk about them as a cohensive feature called "ownership".

### A bit more detail

The basic problem with Swift's current ownership system
is copies, and all three tentpoles of ownership are about
avoiding copies.

A value may be used in many different places in a program.
The implementation has to ensure that some copy of the value
survives and is usable at each of these places. As long as
a type is copyable, it's always possible to satisfy that by
making more copies of the value. However, most uses don't
actually require ownership of their own copy. Some do: a
variable that didn't own its current value would only be
able to store values that were known to be owned by something
else, which isn't very useful in general. But a simple thing
like reading a value out of a class instance only requires that
the instance still be valid, not that the code doing the
read actually own a reference to it itself. Sometimes the
difference is obvious, but often it's impossible to know.
For example, the compiler generally doesn't know how an
arbitrary function will use its arguments; it just falls
back on a default rule for whether to pass ownership of
the value. When that default rule is wrong, the program
will end up making extra copies at runtime. So one simple
thing we can do is allow programs to be more explicit at
certain points about whether they need ownership or not.

That closely dovetails with the desire to support non-copyable
types. Most resources require a unique point of destruction:
a memory allocation can only be freed once, a file can only
be closed once, a lock can only be released once, and so on.
An owning reference to such a resource is therefore naturally
unique and thus non-copyable. Of course, we can artificially
allow ownership to be shared by, say, adding a reference count
and only destroying the resource when the count reaches zero.
But this can substantially increase the overhead of working
with the resource; and worse, it introduces problems with
concurrency and re-entrancy. If ownership is unique, and the
language can enforce that certain operations on a resource
can only be performed by the code that owns the resource,
then by construction only one piece of code can perform those
operations at a time. As soon as ownership is shareable,
that property disappears. So it is interesting for the
language to directly support non-copyable types because they
allow the expression of optimally-efficient abstractions
over resources. However, working with such types requires
all of the abstraction points like function arguments to
be correctly annotated about whether they transfer ownership,
because the compiler can no longer just make things work
behind the scenes by adding copies.

Solving either of these problems well will require us to
also solve the problem of non-exclusive access to variables.
Swift today allows nested accesses to the same variable;
for example, a single variable can be passed as two different
`inout` arguments, or a method can be passed a callback that
somehow accesses the same variable that the method was called on.
Doing this is mostly discouraged, but it's not forbidden,
and both the compiler and the standard library have to bend
over backwards to ensure that the program won't misbehave
too badly if it happens. For example, `Array` has to retain
its buffer during an in-place element modification; otherwise,
if that modification somehow reassigned the array variable,
the buffer would be freed while the element was still being
changed. Similarly, the compiler generally finds it difficult
to prove that values in memory are the same at different points
in a function, because it has to assume that any opaque
function call might rewrite all memory; as a result, it
often has to insert copies or preserve redundant loads
out of paranoia. Worse, non-exclusive access greatly
limits the usefulness of explicit annotations. For example,
a "shared" argument is only useful if it's really guaranteed
to stay valid for the entire call, but the only way to
reliably satisfy that for the current value of a variable
that can be re-entrantly modified is to make a copy and pass
that instead. It also makes certain important patterns
impossible, like stealing the current value of a variable
in order to build something new; this is unsound if the
variable can be accessed by other code in the middle.
The only solution to this is to establish a rule that prevents
multiple contexts from accessing the same variable at the
same time. This is what we propose to do with the Law
of Exclusivity.

All three of these goals are closely linked and mutually
reinforcing. The Law of Exclusivity allows explicit annotations
to actually optimize code by default and enables mandatory
idioms for non-copyable types. Explicit annotations create
more optimization opportunities under the Law and enable
non-copyable types to function. Non-copyable types validate
that annotations are optimal even for copyable types and
create more situations where the Law can be satisfied statically.

### Criteria for success

As discussed above, it is the core team's expectation that
ownership can be delivered as an opt-in enhancement to Swift.
Programmers should be able to largely ignore ownership and not
suffer for it. If this expectation proves to not be satisfiable,
we will reject ownership rather than imposing substantial
burdens on regular programs.

The Law of Exclusivity will impose some new static and dynamic
restrictions. It is our belief that these restrictions will only
affect a small amount of code, and only code that does things
that we already document as producing unspecified results.
These restrictions, when enforced dynamically, will also hurt
performance. It is our hope that this will be "paid for" by
the improved optimization potential. We will also provide tools
for programmers to eliminate these safety checks where necessary.
We will discuss these restrictions in greater detail later in this
document.

## Core definitions

### Values

Any discussion of ownership systems is bound to be at a lower
level of abstraction. We will be talking a lot about
implementation topics. In this context, when we say "value",
we mean a specific instance of a semantic, user-language value.

For example, consider the following Swift code:

var x = [1,2,3]
var y = x

People would often say that `x` and `y` have the same value
at this point. Let's call this a *semantic value*. But at
the level of the implementation, because the variables `x` and `y`
can be independently modified, the value in `y` must be a
copy of the value in `x`. Let's call this a *value instance*.
A value instance can be moved around in memory and remain the
same value instance, but a copy always yields a new value instance.
For the remainder of this document, when we use "value" without any
qualification, we mean it in this low-level sense of value instance.

What it means to copy or destroy a value instance depends on the type:

* Some types do not require extra work besides copying their
byte-representation; we call these *trivial*. For example,
`Int` and `Float` are trivial types, as are ordinary `struct`s
and `enum`s containing only such values. Most of what we have
to say about ownership in this document doesn't apply to the
values of such types. However, the Law of Exclusivity will still
apply to them.

* For reference types, the value instance is a reference to an object.
Copying the value instance means making a new reference, which
increases the reference count. Destroying the value instance means
destroying a reference, which decreases the reference count. Decreasing
the reference count can, of course, drop it to zero and thus destroy
the object, but it's important to remember that all this talk about
copying and destroying values means manipulating reference counts,
not copying the object or (necessarily) destroying it.

* For copy-on-write types, the value instance includes a reference to
a buffer, which then works basically like a reference type. Again,
it is important to remember that copying the value doesn't mean
copying the contents of the buffer into a new buffer.

There are similar rules for every kind of type.

### Memory

In general, a value can be owned in one of two ways: it can be
"in flight", a temporary value owned by a specific execution context
which computed the value as an operand, or it can be "at rest",
stored in some sort of memory.

We don't need to focus much on temporary values because their
ownership rules are straightforward. Temporary values are created
as the result of some expression; that expression is used in some
specific place; the value is needed in that place and not
thereafter; so the implementation should clearly take all possible
steps to forward the value directly to that place instead of
forcing it to be copied. Users already expect all of this to
happen, and there's nothing really to improve here.

Therefore, most of our discussion of ownership will center around
values stored in memory. There are five closely related concepts
in Swift's treatment of memory.

A *storage declaration* is the language-syntax concept of a declaration
that can be treated in the language like memory. Currently, these are
always introduced with `let`, `var`, and `subscript`. A storage
declaration has a type. It also has an implementation which defines
what it means to read or write the storage. The default implementation
of a `var` or `let` just creates a new variable to store the value,
but storage declarations can also be computed, and so there needn't
be any variables at all behind one.

A *storage reference expression* is the syntax concept of an expression
that refers to storage. This is similar to the concept from other
languages of an "l-value", except that it isn't necessarily usable on
the left side of an assignment because the storage doesn't have to be
mutable.

A *storage reference* is the language-semantics concept of a fully
filled-in reference to a specific storage declaration. In other
words, it is the result of evaluating a storage reference expression
in the abstract, without actually accessing the storage. If the
storage is a member, this includes a value or storage reference
for the base. If the storage is a subscript, this includes a value
for the index. For example, a storage reference expression like
`widgets[i].weight` might abstractly evaluate to this storage reference:

* the storage for the property `var weight: Double` of
* the storage for the subscript `subscript(index: Int)` at index value `19: Int` of
* the storage for the local variable `var widgets: [Widget]`

A *variable* is the semantics concept of a unique place in
memory that stores a value. It's not necessarily mutable, at least
as we're using it in this document. Variables are usually created for
storage declarations, but they can also be created dynamically in
raw memory, e.g. using UnsafeRawPointer. A variable always has a
specific type. It also has a *lifetime*, i.e. a point in the language
semantics where it comes into existence and a point (or several)
where it is destroyed.

A *memory location* is a contiguous range of addressable memory. In
Swift, this is mostly an implementation concept. Swift does not
guarantee that any particular variable will have a consistent memory
location throughout its lifetime, or in fact be stored in a memory
location at all. But a variable can sometimes be temporarily forced
to exist at a specific, consistent location: e.g. it can be passed
`inout` to `withUnsafeMutablePointer`.

### Accesses

A particular evaluation of a storage reference expression is
called an access. Accesses come in three kinds: *reads*,
*assignments*, and *modifications*. Assignments and modifications
are both *writes*, with the difference being that an assignment
completely replaces the old value without reading it, while a
modification does rely on the old value.

All storage reference expressions are classified into one of these
three kinds of access based on the context in which the expression
appears. It is important to note that this decision is superficial:
it relies only on the semantic rules of the immediate context, not
on a deeper analysis of the program or its dynamic behavior.
For example, a storage reference passed as an `inout` argument
is always evaluated as a modification in the caller, regardless
of whether the callee actually uses the current value, performs
any writes to it, or even refers to it at all.

The evaluation of a storage reference expression is divided into
two phases: it is first formally evaluated to a storage reference,
and then a formal access to that storage reference occurs for some
duration. The two phases are often evaluated in immediate
succession, but they can be separated in complex cases, such as
when an `inout` argument is not the last argument to a call.
The purpose of this phase division is to minimize the duration of
the formal access while still preserving, to the greatest extent
possible, Swift's left-to-right evaluation rules.

## The Law of Exclusivity

With all of that established, we can succinctly state the first
part of this proposal, the Law of Exclusivity:

If a storage reference expression evaluates to a storage
reference that is implemented by a variable, then the formal
access duration of that access may not overlap the formal
access duration of any other access to the same variable
unless both accesses are reads.

This is intentionally vague: it merely says that accesses
"may not" overlap, without specifying how that will be
enforced. This is because we will use different enforcement
mechanisms for different kinds of storage. We will discuss
those mechanisms in the next major section. First, however,
we need to talk in general about some of the implications of
this rule and our approach to satisfying it.

### Duration of exclusivity

The Law says that accesses must be exclusive for their entire
formal access duration. This duration is determined by the
immediate context which causes the access; that is, it's a
*static* property of the program, whereas the safety problems
we laid out in the introduction are *dynamic*. It is a general
truth that static approaches to dynamic problems can only be
conservatively correct: there will be dynamically-reasonable
programs that are nonetheless rejected. It is fair to ask how
that general principle applies here.

For example, when storage is passed as an `inout` argument, the
access lasts for the duration of the call. This demands
caller-side enforcement that no other accesses can occur to
that storage during the call. Is it possible that this is too
coarse-grained? After all, there may be many points within the
called function where it isn't obviously using its `inout`
argument. Perhaps we should track accesses to `inout` arguments
at a finer-grained level, within the callee, instead of attempting
to enforce the Law of Exclusivity in the caller. The problem
is that that idea is simply too dynamic to be efficiently
implemented.

A caller-side rule for `inout` has one key advantage: the
caller has an enormous amount of information about what
storage is being passed. This means that a caller-side rule
can often be enforced purely statically, without adding dynamic
checks or making paranoid assumptions. For example, suppose
that a function calls a `mutating` method on a local variable.
(Recall that `mutating` methods are passed `self` as an `inout`
argument.) Unless the variable has been captured in an
escaping closure, the function can easily examine every
access to the variable to see that none of them overlap
the call, thus proving that the rule is satisfied. Moreover,
that guarantee is then passed down to the callee, which can
use that information to prove the safety of its own accesses.

In contrast, a callee-side rule for `inout` cannot take
advantage of that kind of information: the information is
simply discarded at the point of the call. This leads to the
widespread optimization problems that we see today, as
discussed in the introduction. For example, suppose that
the callee loads a value from its argument, then calls
a function which the optimizer cannot reason about:

extension Array {
  mutating func organize(_ predicate: (Element) -> Bool) {
    let first = self[0]
    if !predicate(first) { return }
    ...
    // something here uses first
  }
}

Under a callee-side rule, the optimizer must copy `self[0]`
into `first` because it must assume (paranoidly) that
`predicate` might somehow turn around and modify the
variable that `self` was bound to. Under a caller-side
rule, the optimizer can use the copy of value held in the
array element for as long as it can continue to prove that
the array hasn't been modified.

Moreover, as the example above suggests, what sort of code
would we actually be enabling by embracing a callee-side rule?
A higher-order operation like this should not have to worry
about the caller passing in a predicate that re-entrantly
modifies the array. Simple implementation choices, like
making the local variable `first` instead of re-accessing
`self[0]` in the example above, would become semantically
important; maintaining any sort of invariant would be almost
inconceivable. It is no surprise that Swift's libraries
generally forbid this kind of re-entrant access. But,
since the library can't completely prevent programmers
from doing it, the implementation must nonetheless do extra
work at runtime to prevent such code from running into
undefined behavior and corrupting the process. Because it
exists solely to work around the possibility of code that
should never occur in a well-written program, we see this
as no real loss.

Therefore, this proposal generally proposes access-duration
rules like caller-side `inout` enforcement, which allow
substantial optimization opportunities at little semantic
cost.

### Components of value and reference types

We've been talking about *variables* a lot. A reader might
reasonably wonder what all this means for *properties*.

Under the definition we laid out above, a property is a
storage declaration, and a stored property creates a
corresponding variable in its container. Accesses to that
variable obviously need to obey the Law of Exclusivity, but are
there any additional restrictions in play due to the fact
that the properties are organized together into a container?
In particular, should the Law of Exclusivity prevent accesses
to different properties of the same variable or value from
overlapping?

Properties can be classified into three groups:
- instance properties of value types,
- instance properties of reference types, and
- `static` and `class` properties on any kind of type.

We propose to always treat reference-type and `static` properties
as independent from one another other, but to treat value-type
properties as generally non-independent outside of a specific
(but important) special case. That's a potentially significant
restriction, and it's reasonable to wonder both why it's necessary
and why we need to draw this distinction between different
kinds of property. There are three reasons.

#### Independence and containers

The first relates to the container.

For value types, it is possible to access both an individual
property and the entire aggregate value. It is clear that an
access to a property can conflict with an access to the aggregate,
because an access to the aggregate is essentially an access to
all of the properties at once. For example, consider a variable
(not necessarily a local one) `p: Point` with stored properties
`x`, `y`, and `z`. If it were possible to simultaneously and
independently modify `p` and `p.x`, that would be an enormous
hole in the Law of Exclusivity. So we do need to enforce the
Law somehow here. We have three options.

(This may make more sense after reading the main section
about enforcing the Law.)

The first option is to simply treat `p.x` as also an access to `p`.
This neatly eliminates the hole because whatever enforcement
we're using for `p` will naturally prevent conflicting accesses
to it. But this will also prevent accesses to different
properties from overlapping, because each will cause an access
to `p`, triggering the enforcement.

The other two options involve reversing that relationship.
We could split enforcement out for all the individual stored
properties, not for the aggregate: an access to `p` would be
treated as an access to `p.x`, `p.y`, and `p.z`. Or we could
parameterize enforcement and teach it to record the specific
path of properties being accessed: "", ".x", and so on.
Unfortunately, there are two problems with these schemes.
The first is that we don't always know the full set of
properties, or which properties are stored; the implementation
of a type might be opaque to us due to e.g. generics or
resilience. An access to a computed property must be treated
as an access to the whole value because it involves passing
the variable to a getter or setter either `inout` or `shared`;
thus it does actually conflict with all other properties.
Attempting to make things work despite that by using dynamic
information would introduce ubiquitous bookkeeping into
value-type accessors, endangering the core design goal of
value types that they serve as a low-cost abstraction tool.
The second is that, while these schemes can be applied to
static enforcement relatively easily, applying them to
dynamic enforcement would require a fiendish amount of
bookkeeping to be carried out dynamically; this is simply
not compatible with our performance goals.

Thus, while there is a scheme which allows independent access
to different properties of the same aggregate value, it
requires us to be using static enforcement for the aggregate
access and to know that both properties are stored. This is an
important special case, but it is just a special case.
In all other cases, we must fall back on the general rule
that an access to a property is also an access to the aggregate.

These considerations do not apply to `static` properties and
properties of reference types. There are no language constructs
in Swift which access every property of a class simultaneously,
and it doesn't even make sense to talk about "every" `static`
property of a type because an arbitrary module can add a new
one at any time.

#### Idioms of independent access

The second relates to user expectations.

Preventing overlapping accesses to different properties of a
value type is at most a minor inconvenience. The Law of Exclusivity
prevents "spooky action at a distance" with value types anyway:
for example, calling a method on a variable cannot kick off a
non-obvious sequence of events which eventually reach back and
modify the original variable, because that would involve two
conflicting and overlapping accesses to the same variable.

In contrast, many established patterns with reference types
depend on exactly that kind of notification-based update. In
fact, it's not uncommon in UI code for different properties of
the same object to be modified concurrently: one by the UI and
the other by some background operation. Preventing independent
access would break those idioms, which is not acceptable.

As for `static` properties, programmers expect them to be
independent global variables; it would make no sense for
an access to one global to prevent access to another.

#### Independence and the optimizer

The third relates to the optimization potential of properties.

Part of the purpose of the Law of Exclusivity is that it
allows a large class of optimizations on values. For example,
a non-`mutating` method on a value type can assume that `self`
remains exactly the same for the duration of the method. It
does not have to worry that an unknown function it calls
in the middle will somehow reach back and modify `self`,
because that modification would violate the Law. Even in a
`mutating` method, no code can access `self` unless the
method knows about it. Those assumptions are extremely
important for optimizing Swift code.

However, these assumptions simply cannot be done in general
for the contents of global variables or reference-type
properties. Class references can be shared arbitrarily,
and the optimizer must assume that an unknown function
might have access to the same instance. And any code in
the system can potentially access a global variable (ignoring
access control). So the language implementation would
gain little to nothing from treating accesses to different
properties as non-independent.

#### Subscripts

Much of this discussion also applies to subscripts, though
in the language today subscripts are never technically stored.
Accessing a component of a value type through a subscript
is treated as accessing the entire value, and so is considered
to overlap any other access to the value. The most important
consequence of this is that two different array elements cannot
be simultaneously accessed. This will interfere with certain
common idioms for working with arrays, although some cases
(like concurrently modifying different slices of an array)
are already quite problematic in Swift. We believe that we
can mitigate the majority of the impact here with targetted
improvements to the collection APIs.

## Enforcing the Law of Exclusivity

There are three available mechanisms for enforcing the Law of
Exclusivity: static, dynamic, and undefined. The choice
of mechanism must be decidable by a simple inspection of the
storage declaration, because the definition and all of its
direct accessors must agree on how it is done. Generally,
it will be decided by the kind of storage being declared,
its container (if any), and any attributes that might be
present.

### Static enforcement

Under static enforcement, the compiler detects that the
law is being violated and reports an error. This is the
preferred mechanism where possible because it is safe, reliable,
and imposes no runtime costs.

This mechanism can only be used when it is perfectly decidable.
For example, it can be used for value-type properties because
the Law, recursively applied, ensures that the base storage is
being exclusively accessed. It cannot be used for ordinary
reference-type properties because there is no way to prove in
general that a particular object reference is the unique
reference to an object. However, if we supported
uniquely-referenced class types, it could be used for their
properties.

In some cases, where desired, the compiler may be able to
preserve source compatibility and avoid an error by implicitly
inserting a copy instead. This likely something we would only
do in a source-compatibility mode.

Static enforcement will be used for:

- immutable variables of all kinds,

- local variables, except as affected by the use of closures
(see below),

- `inout` arguments, and

- instance properties of value types.

### Dynamic enforcement

Under dynamic enforcement, the implementation will maintain
a record of whether each variable is currently being accessed.
If a conflict is detected, it will trigger a dynamic failure.
The compiler may emit an error statically if it detects that
dynamic enforcement will always detect a conflict.

The bookkeeping requires two bits per variable, using a tri-state
of "unaccessed", "read", and "modified". Although multiple
simultaneous reads can be active at once, a full count can be
avoided by saving the old state across the access, with a little
cleverness.

The bookkeeping is intended to be best-effort. It should reliably
detect deterministic violations. It is not required to detect
race conditions; it often will, and that's good, but it's not
required to. It *is* required to successfully handle the case
of concurrent reads without e.g. leaving the bookkeeping record
permanently in the "read" state. But it is acceptable for the
concurrent-reads case to e.g. leave the bookkeeping record in
the "unaccessed" case even if there are still active readers;
this permits the bookkeeping to use non-atomic operations.
However, atomic operations would have to be used if the bookkeeping
records were packed into a single byte for, say, different
properties of a class, because concurrent accesses are
allowed on different variables within a class.

When the compiler detects that an access is "instantaneous",
in the sense that none of the code executed during the access
can possibly cause a re-entrant access to the same variable,
it can avoid updating the bookkeeping record and instead just
check that it has an appropriate value. This is common for
reads, which will often simply copy the value during the access.
When the compiler detects that all possible accesses are
instantaneous, e.g. if the variable is `private` or `internal`,
it can eliminate all bookkeeping. We expect this to be fairly
common.

Dynamic enforcement will be used for:

- local variables, when necessary due to the use of closures
(see below),

- instance properties of class types,

- `static` and `class` properties, and

- global variables.

We should provide an attribute to allow dynamic enforcement
to be downgraded to undefined enforcement for a specific
property or class. It is likely that some clients will find
the performance consequences of dynamic enforcement to be
excessive, and it will be important to provide them an opt-out.
This will be especially true in the early days of the feature,
while we're still exploring implementation alternatives and
haven't yet implemented any holistic optimizations.

Future work on isolating class instances may allow us to
use static enforcement for some class instance properties.

### Undefined enforcement

Undefined enforcement means that conflicts are not detected
either statically or dynamically, and instead simply have
undefined behavior. This is not a desireable mechanism
for ordinary code given Swift's "safe by default" design,
but it's the only real choice for things like unsafe pointers.

Undefined enforcement will be used for:

- the `memory` properties of unsafe pointers.

### Enforcement for local variables captured by closures

Our ability to statically enforce the Law of Exclusivity
relies on our ability to statically reason about where
uses occur. This analysis is usually straightforward for a
local variable, but it becomes complex when the variable is
captured in a closure because the control flow leading to
the use can be obscured. A closure can potentially be
executed re-entrantly or concurrently, even if it's known
not to escape. The following principles apply:

- If a closure `C` potentially escapes, then for any variable
`V` captured by `C`, all accesses to `V` potentially executed
after a potential escape (including the accesses within `C`
itself) must use dynamic enforcement unless all such acesses
are reads.

- If a closure `C` does not escape a function, then its
use sites within the function are known; at each, the closure
is either directly called or used as an argument to another
call. Consider the set of non-escaping closures used at
each such call. For each variable `V` captured by `C`, if
any of those closures contains a write to `V`, all accesses
within those closures must use dynamic enforcement, and
the call is treated for purposes of static enforcement
as if it were a write to `V`; otherwise, the accesses may use
static enforcement, and the call is treated as if it were a
read of `V`.

It is likely that these rules can be improved upon over time.
For example, we should be able to improve on the rule for
direct calls to closures.

## Explicit tools for ownership

### Shared values

A lot of the discussion in this section involves the new concept
of a *shared value*. As the name suggests, a shared value is a
value that has been shared with the current context by another
part of the program that owns it. To be consistent with the
Law of Exclusivity, because multiple parts of the program can
use the value at once, it must be read-only in all of them
(even the owning context). This concept allows programs to
abstract over values without copying them, just like `inout`
allows programs to abstract over variables.

(Readers familiar with Rust will see many similarities between
shared values and Rust's concept of an immutable borrow.)

When the source of a shared value is a storage reference, the
shared value acts essentially like an immutable reference
to that storage. The storage is accessed as a read for the
duration of the shared value, so the Law of Exclusivity
guarantees that no other accesses will be able to modify the
original variable during the access. Some kinds of shared
value may also bind to temporary values (i.e. an r-value).
Since temporary values are always owned by the current
execution context and used in one place, this poses no
additional semantic concerns.

A shared value can be used in the scope that binds it
just like an ordinary parameter or `let` binding.
If the shared value is used in a place that requires
ownership, Swift will simply implicitly copy the value —
again, just like an ordinary parameter or `let` binding.

#### Limitations of shared values

This section of the document describes several ways to form
and use shared values. However, our current design does not
provide general, "first-class" mechanisms for working with them.
A program cannot return a shared value, construct an array
of shared values, store shared values into `struct` fields,
and so on. These limitations are similar to the existing
limitations on `inout` references. In fact, the similarities
are so common that it will be useful to have a term that
encompasses both: we will call them *ephemerals*.

The fact that our design does not attempt to provide first-class
facilities for ephemerals is a well-considered decision,
born from a trio of concerns:

- We have to scope this proposal to something that can
conceivably be implemented in the coming months. We expect this
proposal to yield major benefits to the language and its
implementaton, but it is already quite broad and aggressive.
First-class ephemerals would add enough complexity to the
implementation and design that they are clearly out of scope.
Furthermore, the remaining language-design questions are
quite large; several existing languages have experimented
with first-class ephemerals, and the results haven't been
totally satisfactory.

- Type systems trade complexity for expressivity.
You can always accept more programs by making the type
system more sophisticated, but that's not always a good
trade-off. The lifetime-qualification systems behind
first-class references in languages like Rust add a lot
of complexity to the user model. That complexity has real
costs for users. And it's still inevitably necessary
to sometimes drop down to unsafe code to work around the
limitations of the ownership system. Given that a line
does have to drawn somewhere, it's not completely settled
that lifetime-qualification systems deserve to be on the
Swift side of the line.

- A Rust-like lifetime system would not necessarily be
as powerful in Swift as it is in Rust. Swift intentionally
provides a language model which reserves a lot of
implementation flexibility to both the authors of types
and to the Swift compiler itself.

For example, polymorphic storage is quite a bit more
flexible in Swift than it is in Rust. A
`MutableCollection` in Swift is required to implement a
`subscript` that provides accessor to an element for an index,
but the implementation can satisfy this pretty much any way
it wants. If generic code accesses this `subscript`, and it
happens to be implemented in a way that provides direct access
to the underlying memory, then the access will happen in-place;
but if the `subscript` is implemented with a computed getter
and setter, then the access will happen in a temporary
variable and the getter and setter will be called as necessary.
This only works because Swift's access model is highly
lexical and maintains the ability to run arbitrary code
at the end of an access. Imagine what it would take to
implement a loop that added these temporary mutable
references to an array — each iteration of the loop would
have to be able to queue up arbitrary code to run as a clean-up
when the function was finished with the array. This would
hardly be a low-cost abstraction! A more Rust-like
`MutableCollection` interface that worked within the
lifetime rules would have to promise that the `subscript`
returned a pointer to existing memory; and that wouldn't
allow a computed implementation at all.

A similar problem arises even with simple `struct` members.
The Rust lifetime rules say that, if you have a pointer to
a `struct`, you can make a pointer to a field of that `struct`
and it'll have the same lifetime as the original pointer.
But this assumes not only that the field is actually stored
in memory, but that it is stored *simply*, such that you can
form a simple pointer to it and that pointer will obey the
standard ABI for pointers to that type. This means that
Rust cannot use layout optimizations like packing boolean
fields together in a byte or even just decreasing the
alignment of a field. This is not a guarantee that we are
willing to make in Swift.

For all of these reasons, while we remain theoretically
interested in exploring the possibilities of a more
sophisticated system that would allow broader uses of
ephemerals, we are not proposing to take that on now. Since
such a system would primarily consist of changes to the type
system, we are not concerned that this will cause ABI-stability
problems in the long term. Nor are we concerned that we will
suffer from source incompatibilities; we believe that any
enhancements here can be done as extensions and generalizations
of the proposed features.

### Local ephemeral bindings

It is already a somewhat silly limitation that Swift provides
no way to abstract over storage besides passing it as an
`inout` argument. It's an easy limitation to work around,
since programmers who want a local `inout` binding can simply
introduce a closure and immediately call it, but that's an
awkward way of achieving something that ought to be fairly easy.

Shared values make this limitation even more apparent, because
a local shared value is an interesting alternative to a local `let`:
it avoids a copy at the cost of preventing other accesses to
the original storage. We would not encourage programmers to
use `shared` instead of `let` throughout their code, especially
because the optimizer will often be able to eliminate the copy
anyway. However, the optimizer cannot always remove the copy,
and so the `shared` micro-optimization can be useful in select
cases. Furthermore, eliminating the formal copy may also be
semantically necessary when working with non-copyable types.

We propose to remove this limitation in a straightforward way:

inout root = &tree.root

shared elements = self.queue

The initializer is required and must be a storage reference
expression. The access lasts for the remainder of the scope.

### Function parameters

Function parameters are the most important way in which
programs abstract over values. Swift currently provides
three kinds of argument-passing:

- Pass-by-value, owned. This is the rule for ordinary
arguments. There is no way to spell this explicitly.

- Pass-by-value, shared. This is the rule for the `self`
arguments of `nonmutating` methods. There is no way to
spell this explicitly.

- Pass-by-reference. This is the rule used for `inout`
arguments and the `self` arguments of `mutating` methods.

Our proposal here is just to allow the non-standard
cases to be spelled explicitly:

- A function argument can be explicitly declared `owned`:

  func append(_ values: owned [Element]) {
    ...
  }

This cannot be combined with `shared` or `inout`.

This is just an explicit way of writing the default, and
we do not expect that users will write it often unless
they're working with non-copyable types.

- A function argument can be explicitly declared `shared`.

  func ==(left: shared String, right: shared String) -> Bool {
    ...
  }

This cannot be combined with `owned` or `inout`.

If the function argument is a storage reference expression,
that storage is accessed as a read for the duration of the
call. Otherwise, the argument expression is evaluated as
an r-value and that temporary value is shared for the call.
It's important to allow temporary values to be shared for
function arguments because many function parameters will be
marked as `shared` simply because the functions don't
actually from owning that parameter, not because it's in
any way semantically important that they be passed a
reference to an existing variable. For example, we expect
to change things like comparison operators to take their
parameters `shared`, because it needs to be possible to
compare non-copyable values without claiming them, but
this should not prevent programmers from comparing things
to literal values.

Like `inout`, this is part of the function type. Unlike
`inout`, most function compatibility checks (such as override
and function conversion checking) should succeed with a
`shared` / `owned` mismatch. If a function with an `owned`
parameter is converted to (or overrides) a function with a
`shared` parameter, the argument type must actually be
copyable.

- A method can be explicitly declared `consuming`.

  consuming func moveElements(into collection: inout [Element]) {
    ...
  }

This causes `self` to be passed as an owned value and therefore
cannot be combined with `mutating` or `nonmutating`.

`self` is still an immutable binding within the method.

### Function results

As discussed at the start of this section, Swift's lexical
access model does not extend well to allowing ephemerals
to be returned from functions. Performing an access requires
executing storage-specific code at both the beginning and
the end of the access. After a function returns, it has no
further ability to execute code.

We could, conceivably, return a callback along with the
ephemeral, with the expectation that the callback will be
executed when the caller is done with the ephemeral.
However, this alone would not be enough, because the callee
might be relying on guarantees from its caller. For example,
considering a `mutating` method on a `struct` which wants
to returns an `inout` reference to a stored property. The
correctness of this depends not only on the method being able
to clean up after the access to the property, but on the
continued validity of the variable to which `self` was bound.
What we really want is to maintain the current context in the
callee, along with all the active scopes in the caller, and
simply enter a new nested scope in the caller with the
ephemeral as a sort of argument. But this is a well-understood
situation in programming languages: it is just a kind of
co-routine. (Because of the scoping restrictions, it can
also be thought of as sugar for a callback function in
which `return`, `break`, etc. actually work as expected.)

In fact, co-routines are useful for solving a number of
problems relating to ephemerals. We will explore this
idea in the next few sub-sections.

### `for` loops

In the same sense that there are three interesting ways of
passing an argument, we can identify three interesting styles
of iterating over a sequence. Each of these can be expressed
with a `for` loop.

#### Consuming iteration

The first iteration style is what we're already familiar with
in Swift: a consuming iteration, where each step is presented
with an owned value. This is the only way we can iterate over
an arbitrary sequence where the values might be created on demand.
It is also important for working with collections of non-copyable
types because it allows the collection to be destructured and the
loop to take ownership of the elements. Because it takes ownership
of the values produced by a sequence, and because an arbitrary
sequence cannot be iterated multiple times, this is a
`consuming` operation on `Sequence`.

This can be explicitly requested by declaring the iteration
variable `owned`:

for owned employee in company.employees {
  newCompany.employees.append(employee)
}

It is also used implicitly when the requirements for a
non-mutating iteration are not met. (Among other things,
this is necessary for source compatibility.)

The next two styles make sense only for collections.

#### Non-mutating iteration

A non-mutating iteration simply visits each of the elements
in the collection, leaving it intact and unmodified. We have
no reason to copy the elements; the iteration variable can
simply be bound to a shared value. This is a `nonmutating`
operaton on `Collection`.

This can be explicitly requested by declaring the iteration
variable `shared`:

for shared employee in company.employees {
  if !employee.respected { throw CatastrophicHRFailure() }
}

It is also used by default when the sequence type is known to
conform to `Collection`, since this is the optimal way of
iterating over a collection.

for employee in company.employees {
  if !employee.respected { throw CatastrophicHRFailure() }
}

If the sequence operand is a storage reference expression,
the storage is accessed for the duration of the loop. Note
that this means that the Law of Exclusivity will implicitly
prevent the collection from being modified during the
iteration. Programs can explicitly request an iteration
over a copy of the value in that storage by using the `copy`
intrinsic function on the operand.

#### Mutating iteration

A mutating iteration visits each of the elements and
potentially changes it. The iteration variable is an
`inout` reference to the element. This is a `mutating`
operation on `MutableCollection`.

This must be explicitly requested by declaring the
iteration variable `inout`:

for inout employee in company.employees {
  employee.respected = true
}

The sequence operand must be a storage reference expression.
The storage will be accessed for the duraton of the loop,
which (as above) will prevent any other overlapping accesses
to the collection. (But this rule does not apply if the
collection type defines the operation as a non-mutating
operation, which e.g. a reference-semantics collection might.)

#### Expressing mutating and non-mutating iteration

Mutating and non-mutating iteration require the collection
to produce ephemeral values at each step. There are several
ways we could express this in the language, but one reasonable
approach would be to use co-routines. Since a co-routine does
not abandon its execution context when yielding a value to its
caller, it is reasonable to allow a co-routine to yield
multiple times, which corresponds very well to the basic
code pattern of a loop. This produces a kind of co-routine
often called a generator, which is used in several major
languages to conveniently implement iteration. In Swift,
to follow this pattern, we would need to allow the definition
of generator functions, e.g.:

mutating generator iterateMutable() -> inout Element {
  var i = startIndex, e = endIndex
  while i != e {
    yield &self[i]
    self.formIndex(after: &i)
  }
}

On the client side, it is clear how this could be used to
implement `for` loops; what is less clear is the right way to
allow generators to be used directly by code. There are
interesting constraints on how the co-routine can be used
here because, as mentioned above, the entire co-routine
must logically execute within the scope of an access to the
base value. If, as is common for generators, the generator
function actually returns some sort of generator object,
the compiler must ensure that that object does not escape
that enclosing access. This is a significant source of
complexity.

### Generalized accessors

Swift today provides very coarse tools for implementing
properties and subscripts: essentially, just `get` and `set`
methods. These tools are inadequate for tasks where
performance is critical because they don't allow direct
access to values without copies. The standard library
has access to a slightly broader set of tools which can
provide such direct access in limited cases, but they're
still quite weak, and we've been reluctant to expose them to
users for a variety of reasons.

Ownership offers us an opportunity to revisit this problem
because `get` doesn't work for collections of non-copyable
types because it returns a value, which must therefore be
owned. The accessor really needs to be able to yield a
shared value instead of returning an owned one. Again,
one reasonable approach for allowing this is to use a
special kind of co-routine. Unlike a generator, this
co-routine would be required to yield exactly once.
And there is no need to design an explicit way for programmers
to invoke one because these would only be used in accessors.

The idea is that, instead of defining `get` and `set`,
a storage declaration could define `read` and `modify`:

var x: String
var y: String
var first: String {
  read {
    if x < y { yield x }
    else { yield y }
  }
  modify {
    if x < y { yield &x }
    else { yield &y }
  }
}

A storage declaration must define either a `get` or a `read`
(or be a stored property), but not both.

To be mutable, a storage declaration must also define either a
`set` or a `modify`. It may also choose to define *both*, in
which case `set` will be used for assignments and `modify` will
be used for modifications. This is useful for optimizing
certain complex computed properties because it allows modifications
to be done in-place without forcing simple assignments to first
read the old value; however, care must be taken to ensure that
the `modify` is consistent in behavior with the `get` and the
`set`.

### Intrinsic functions

#### `move`

The Swift optimizer will generally try to move values around
instead of copying them, but it can be useful to force its hand.
For this reason, we propose the `move` function. Conceptually,
`move` is simply a top-level function in the Swift standard
library:

func move<T>(_ value: T) -> T {
  return value
}

However, it is blessed with some special semantics. It cannot
be used indirectly. The argument expression must be a reference
to some kind of local owning storage: either a `let`, a `var`,
or an `inout` binding. A call to `move` is evaluated by
semantically moving the current value out of the argument
variable and returning it as the type of the expression,
leaving the variable uninitialized for the purposes of the
definitive-initialization analysis. What happens with the
variable next depends on the kind of variable:

- A `var` simply transitions back to being uninitialized.
Uses of it are illegal until it is assigned a new value and
thus reinitialized.

- An `inout` binding is just like a `var`, except that it is
illegal for it to go out of scope uninitialized. That is,
if a program moves out of an `inout` binding, the program
must assign a new value to it before it can exit the scope
in any way (including by throwing an error). Note that the
safety of leaving an `inout` temporarily uninitialized
depends on the Law of Exclusivity.

- A `let` cannot be reinitialized and so cannot be used
again at all.

This should be a straightforward addition to the existing
definitive-initialization analysis, which proves that local
variables are initialized before use.

#### `copy`

`copy` is a top-level function in the Swift standard library:

func copy<T>(_ value: T) -> T {
  return value
}

The argument must be a storage reference expression. The
semantics are exactly as given in the above code: the argument
value is returned. This is useful for several reasons:

- It suppresses syntactic special-casing. For example, as
discussed above, if a `shared` argument is a storage
reference, that storage is normally accessed for the duration
of the call. The programmer can suppress this and force the
copy to complete before the call by calling `copy` on the
storage reference before

- It is necessary for types that have suppressed implicit
copies. See the section below on non-copyable types.

#### `endScope`

`endScope` is a top-level function in the Swift standard library:

func endScope<T>(_ value: T) -> () {}

The argument must be a reference to a local `let`, `var`, or
standalone (non-parameter, non-loop) `inout` or `shared`
declaration. If it's a `let` or `var`, the variable is
immediately destroyed. If it's an `inout` or `shared`,
the access immediately ends.

The definitive-initialization analysis must prove that
the declaration is not used after this call. It's an error
if the storage is a `var` that's been captured in an escaping
closure.

This is useful for ending an access before control reaches the
end of a scope, as well as for micro-optimizing the destruction
of values.

`endScope` provides a guarantee that the given variable has
been destroyed, or the given access has ended, by the time
of the execution of the call. It does not promise that these
things happen exactly at that point: the implementation is
still free to end them earlier.

### Lenses

Currently, all storage reference expressions in Swift are *concrete*:
every component is statically resolvable to a storage declaration.
There is some recurring interest in the community in allowing programs
to abstract over storage, so that you might say:

let prop = Widget.weight

and then `prop` would be an abstract reference to the `weight`
property, and its type would be something like `(Widget) -> Double`.

This feature is relevant to the ownership model because an ordinary
function result must be an owned value: not shared, and not mutable.
This means lenses could only be used to abstract *reads*, not
*writes*, and could only be created for copyable properties. It
also means code using lenses would involve more copies than the
equivalent code using concrete storage references.

Suppose that, instead of being simple functions, lenses were their
own type of value. An application of a lens would be a storage
reference expression, but an *abstract* one which accessed
statically-unknown members. This would require the language
implementation to be able to perform that sort of access
dynamically. However, the problem of accessing an unknown
property is very much like the problem of accessing a known
property whose implementation is unknown; that is, the language
already has to do very similar things in order to implement
generics and resilience.

Overall, such a feature would fit in very neatly with the
ownership model laid out here.

## Non-copyable types

Non-copyable types are useful in a variety of expert situations.
For example, they can be used to efficiently express unique
ownership. They are also interesting for expressing values
that have some sort of independent identity, such as atomic
types. They can also be used as a formal mechanism for
encouraging code to work more efficiently with types that
might be expensive to copy, such as large struct types. The
unifying theme is that we do not want to allow the type to
be copied implicitly.

The complexity of handling non-copyable types in Swift
comes from two main sources:

- The language must provide tools for moving values around
and sharing them without forcing copies. We've already
proposed these tools in this document because they're
equally important for optimizing the use of copyable types.

- The generics system has to be able to express generics over
non-copyable types without massively breaking source
compatibility and forcing non-copyable types on everybody.

Otherwise, the feature itself is pretty small. The compiler
implicitly emits moves instead of copies, just like we discussed
above for the `move` intrinsic, and then diagnoses anything
that that didn't work for.

### `moveonly` contexts

The generics problem is real, though. The most obvious way
to model copyability in Swift is to have a `Copyable`
protocol which types can conform to. An unconstrained type
parameter `T` would then not be assumed to be copyable.
Unfortunately, this would be a disaster for both source
compatibility and usability, because almost all the existing
generic code written in Swift assumes copyability, and
we really don't want programmers to have to worry about
non-copyable types in their first introduction to generic
code.

Furthermore, we don't want types to have to explicitly
declare conformance to `Copyable`. That should be the
default.

The logical solution is to maintain the default assumption
that all types are copyable, and then allow select contexts
to turn that assumption off. We will cause these contexts
`moveonly` contexts. All contexts lexically nested within
a `moveonly` context are also implicitly `moveonly`.

A type can be a `moveonly` context:

moveonly struct Array<Element> {
  // Element and Array<Element> are not assumed to be copyable here
}

This suppresses the `Copyable` assumption for the type
declared, its generic arguments (if any), and their
hierarchies of associated types.

An extension can be a `moveonly` context:

moveonly extension Array {
  // Element and Array<Element> are not assumed to be copyable here
}

A type can declare conditional copyability using a conditional
conformance:

moveonly extension Array: Copyable where Element: Copyable {
  ...
}

Conformance to `Copyable`, conditional or not, is an
inherent property of a type and must be declared in the
same module that defines the type. (Or possibly even the
same file.)

A non-`moveonly` extension of a type reintroduces the
copyability assumption for the type and its generic
arguments. This is necessary in order to allow standard
library types to support non-copyable elements without
breaking compatibility with existing extensions. If the
type doesn't declare any conformance to `Copyable`, giving
it a non-`moveonly` extension is an error.

A function can be a `moveonly` context:

extension Array {
  moveonly func report<U>(_ u: U)
}

This suppresses the copyability assumption for any new
generic arguments and their hierarchies of associated types.

A lot of the details of `moveonly` contexts are still up
in the air. It is likely that we will need substantial
implementation experience before we can really settle on
the right design here.

One possibility we're considering is that `moveonly`
contexts will also suppress the implicit copyability
assumption for values of copyable types. This would
provide an important optimization tool for code that
needs to be very careful about copies.

### `deinit` for non-copyable types

A value type declared `moveonly` which does not conform
to `Copyable` (even conditionally) may define a `deinit`
method. `deinit` must be defined in the primary type
definition, not an extension.

`deinit` will be called to destroy the value when it is
no longer required. This permits non-copyable types to be
used to express the unique ownership of resources. For
example, here is a simple file-handle type that ensures
that the handle is closed when the value is destroyed:

moveonly struct File {
  var descriptor: Int32

  init(filename: String) throws {
    descriptor = Darwin.open(filename, O_RDONLY)

    // Abnormally exiting 'init' at any point prevents deinit
    // from being called.
    if descriptor == -1 { throw ... }
  }

  deinit {
    _ = Darwin.close(descriptor)
  }

  consuming func close() throws {
    if Darwin.fsync(descriptor) != 0 { throw ... }

    // This is a consuming function, so it has ownership of self.
    // It doesn't consume self in any other way, so it will
    // destroy it when it exits by calling deinit.  deinit
    // will then handle actually closing the descriptor.
  }
}

Swift is permitted to destroy a value (and thus call `deinit`)
at any time between its last use and its formal point of
destruction. The exact definition of "use" for the purposes
of this definition is not yet fully decided.

If the value type is a `struct`, `self` can only be used
in `deinit` in order to refer to the stored properties
of the type. The stored properties of `self` are treated
like local `let` constants for the purposes of the
definitive-initialization analysis; that is, they are owned
by the `deinit` and can be moved out of.

If the value type is an `enum`, `self` can only be used
in `deinit` as the operand of a `switch`. Within this
`switch`, any associated values are used to initialize
the corresponding bindings, which take ownership of those
values. Such a `switch` leaves `self` uninitialized.

### Explicitly-copyable types

Another idea in the area of non-copyable types that we're
exploring is the ability to declare that a type cannot
be implicitly copied. For example, a very large struct
can formally be copied, but it might be an outsized
impact on performance if it is copied unnecessarily.
Such a type should conform to `Copyable`, and it should
be possible to request a copy with the `copy` function,
but the compiler should diagnose any implicit copies
the same way that it would diagnose copies of a
non-copyable type.

## Implementation priorities

This document has laid out a large amount of work.
We can summarize it as follows:

- Enforcing the Law of Exclusivity:

- Static enforcement
- Dynamic enforcement
- Optimization of dynamic enforcement

- New annotations and declarations:

- `shared` parameters
- `consuming` methods
- Local `shared` and `inout` declarations

- New intrinsics affecting DI:

- The `move` function and its DI implications
- The `endScope` function and its DI implications

- Co-routine features:

- Generalized accessors
- Generators

- Non-copyable types

- Further design work
- DI enforcement
- `moveonly` contexts

The single most important goal for the upcoming releases is
ABI stability. The prioritization and analysis of these
features must center around their impact on the ABI. With
that in mind, here are the primary ABI considerations:

The Law of Exclusivity affects the ABI because it
changes the guarantees made for parameters. We must adopt
this rule before locking down on the ABI, or else we will
get stuck making conservative assumptions forever.
However, the details of how it is enforced do not affect
the ABI unless we choose to offload some of the work to the
runtime, which is not necessary and which can be changed
in future releases. (As a technical note, the Law
of Exclusivity is likely to have a major impact on the
optimizer; but this is an ordinary project-scheduling
consideration, not an ABI-affecting one.)

The standard library is likely to enthusiastically adopt
ownership annotations on parameters. Those annotations will
affect the ABI of those library routines. Library
developers will need time in order to do this adoption,
but more importantly, they will need some way to validate
that their annotations are useful. Unfortunately, the best
way to do that validation is to implement non-copyable types,
which are otherwise very low on the priority list.

The generalized accessors work includes changing the standard
set of "most general" accessors for properties and subscripts
from `get`/`set`/`materializeForSet` to (essentially)
`read`/`set`/`modify`. This affects the basic ABI of
all polymorphic property and subscript accesses, so it
needs to happen. However, this ABI change can be done
without actually taking the step of allowing co-routine-style
accessors to be defined in Swift. The important step is
just ensuring that the ABI we've settled on is good
enough for co-routines in the future.

The generators work may involve changing the core collections
protocols. That will certainly affect the ABI. In contrast
with the generalized accessors, we will absolutely need
to implement generators in order to carry this out.

Non-copyable types and algorithms only affect the ABI
inasmuch as they are adopted in the standard library.
If the library is going to extensively adopt them for
standard collections, that needs to happen before we
stabilize the ABI.

The new local declarations and intrinsics do not affect the ABI.
(As is often the case, the work with the fewest implications
is also some of the easiest.)

Adopting ownership and non-copyable types in the standard
library is likely to be a lot of work, but will be important
for the usability of non-copyable types. It would be very
limiting if it was not possible to create an `Array`
of non-copyable types.

(end)

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi John,

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.

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.

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.

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.

OK. You got me convinced this is probably the most consistent approach. Do you envision any other policy protocol?

Not right away, but it's possible that eventually we might want equivalents to some of the other magic protocols in Rust, like Send (which IIRC promises that shared references are thread-safe; that's a similar sort of fundamental property).

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?

Well, for one, CPUs may get cleverer here over time. So I would be uncomfortable with cementing this too much in the language.

I don't think this will dramatically improve over time. Moreover, spatial/physical dependencies may not be specific to cache lines. Another example would be two boolean packed into two bits. Those variables are not independent because writing into one of them requires loading and writing both of them (unless you exclusively use atomic operations).

Correct. This design doesn't *completely* give up on allowing bit-packing in classes, but it does make it much harder. That was considered. :)

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.

This indeed wouldn't be statically checkable, but this could be (maybe as an opt-in?) dynamically checked.

Yes, we could certainly do layout dynamically based on the actual cache-line size. But I hope we can agree that putting every class property on its own cache line by default is not actually acceptable. :)

Putting every value in its own cache line would clearly be a disaster.

···

Le 20 févr. 2017 à 23:16, John McCall <rjmccall@apple.com> a écrit :

On Feb 20, 2017, at 4:55 PM, Florent Bruneau <florent.bruneau@intersec.com> wrote:

Le 20 févr. 2017 à 18:22, John McCall <rjmccall@apple.com> a écrit :

On Feb 20, 2017, at 3:40 AM, Florent Bruneau <florent.bruneau@intersec.com> wrote:

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.

Allowing some sort of intelligent layout to prevent cache-line collisions would certainly be a secondary goal of a concurrency design, though.

OK

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.

struct Ressource {
 /* content is unimportant here */
}

class Worker {
 shared ressource: Ressource

 init(ressource: shared Ressource) {
     self.ressource = ressource
 }

 /* ... */
}

let ressource = Ressource()

for i in 0..<10 {
let worker = Worker(ressource: ressource)
worker.schedule()
}
waitAllWorkers()

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?

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.

There may be dynamic approaches that could work. What we want is make sure that no dangling ephemeral remains after the end of life of the pointed ressource. We could imagine a solution based on weak-reference wherever we cannot statically enforce the lifetime rules. In that case, all references to the shared ressource, or all references to objects containing the ephemeral might be enforced to be weak and nil-ified when the value reaches its end of life. I'm aware there is a lot of issues with that idea. The first issue is that another thread may have a strong reference on the Worker because it is running a method of Worker when the Ressource becomes unavailable, which just breaks everything). Another issue is the runtime overhead of the bookkeeping requested to maintain the list of references associated to Ressource.

Actually, it would probably be better to forget that idea :)

Well, you could allocate a refcounted object to do the bookkeeping and then implicitly capture that along with the shared value. That would be quite the perf hit, though.

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?

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.

OK

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.

[1] [swift-evolution] Proposal to improve C pointer type import

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.

Sorry about this. My whole point is simply: how can we make interaction with C safer in order to make it easier to migrate from C to Swift without rewriting everything from scratch. I had no idea you were working on the ownership principles at the time and it clearly looks like a big step toward that goal.

Yeah, I definitely think this has to happen first.

John.

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.

Thx.

Le 17 févr. 2017 à 09:25, John McCall via swift-evolution <swift-evolution@swift.org> a écrit :

Hello, swift-evolution.

Memory ownership is a topic that keeps poking its head up here. Core team
members have mentioned several times that it's something we're interested in
working on. Questions sometimes get referred back to it, saying stuff like
"we're working on tools to let you control ARC a little better". It's even on the
short list of high-priority features for Swift 4:

GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.

Memory ownership model: an (opt-in) Cyclone/Rust-inspired memory
ownership model is highly desired by systems programmers and for other
high-performance applications that want predictable and deterministic
performance. This feature will fundamentally shape the ABI, from low-level
language concerns such as "inout" and low-level "addressors" to its impact
on the standard library. While a full memory ownership model is likely too
large for Swift 4 stage 1, we need a comprehensive design to understand
how it will change the ABI.

But that's all pretty vague. What is ownership? What does it mean for
programmers? Is somebody ever going to actually write that comprehensive
design that was supposed to come out during Stage 1?

Well, here you go.

I want to emphasize that this document is two things. It is a *manifesto*,
because it describes the whole problem and presents a holistic solution to it.
And it is a *meta-proposal*, because that holistic solution imagines and a number
of changes, each of which is worthy of a proposal; it is, essentially, a proposal
that we write a bunch of smaller proposals for each of these changes. But it's
not actually a concrete proposal for those smaller changes: it's often lacking in
that level of detail, and it leaves a number of questions open. This document, itself,
will not undergo the formal evolution process. And it may be that some of these
changes aren't really necessary, or that they need major reconsideration before
they're appropriate for proposal. But our hope — my hope — is that this
document is sufficient for you to understand the holistic approach we're suggesting,
or at least puts you in a position where you're comfortable asking questions
and trying to figure it out.

So, like I said, this isn't a formal proposal. What, then, are we hoping to achieve?
Well, we want people to talk about it. We'd like to achieve a consensus about
whether this basic approach makes sense for the language and achieves its goals.
And, assuming that the consensus is "yes" and that we should go forward with it,
we'd like this document — and this thread — to serve as an introduction to the
topic that we can refer back to when we're proposing and discussing all of those
changes in the weeks to come.

With that said, let's get started.

John.

------------------------------------------------------------------

# Ownership

## Introduction

Adding "ownership" to Swift is a major feature with many benefits
for programmers. This document is both a "manifesto" and a
"meta-proposal" for ownership: it lays out the basic goals of
the work, describes a general approach for achieving those goals,
and proposes a number of specific changes and features, each of
which will need to be separately discussed in a smaller and more
targeted proposal. This document is intended to provide a framework
for understanding the contributions of each of those changes.

### Problem statement

The widespread use of copy-on-write value types in Swift has generally
been a success. It does, however, come with some drawbacks:

* Reference counting and uniqueness testing do impose some overhead.

* Reference counting provides deterministic performance in most cases,
but that performance can still be complex to analyze and predict.

* The ability to copy a value at any time and thus "escape" it forces
the underlying buffers to generally be heap-allocated. Stack allocation
is far more efficient but does require some ability to prevent, or at
least recognize, attempts to escape the value.

Certain kinds of low-level programming require stricter performance
guarantees. Often these guarantees are less about absolute performance
than *predictable* performance. For example, keeping up with an audio
stream is not a taxing job for a modern processor, even with significant
per-sample overheads, but any sort of unexpected hiccup is immediately
noticeable by users.

Another common programming task is to optimize existing code when something
about it falls short of a performance target. Often this means finding
"hot spots" in execution time or memory use and trying to fix them in some
way. When those hot spots are due to implicit copies, Swift's current
tools for fixing the problem are relatively poor; for example, a programmer
can fall back on using unsafe pointers, but this loses a lot of the
safety benefits and expressivity advantages of the library collection types.

We believe that these problems can be addressed with an opt-in set of
features that we collectively call *ownership*.

### What is ownership?

*Ownership* is the responsibility of some piece of code to
eventually cause a value to be destroyed. An *ownership system*
is a set of rules or conventions for managing and transferring
ownership.

Any language with a concept of destruction has a concept of
ownership. In some languages, like C and non-ARC Objective-C,
ownership is managed explicitly by programmers. In other
languages, like C++ (in part), ownership is managed by the
language. Even languages with implicit memory management still
have libraries with concepts of ownership, because there are
other program resources besides memory, and it is important
to understand what code has the responsibility to release
those resources.

Swift already has an ownership system, but it's "under the covers":
it's an implementation detail that programmers have little
ability to influence. What we are proposing here is easy
to summarize:

- We should add a core rule to the ownership system, called
the Law of Exclusivity, which requires the implementation
to prevent variables from being simultaneously accessed
in conflicting ways. (For example, being passed `inout`
to two different functions.) This will not be an opt-in
change, but we believe that most programs will not be
adversely affected.

- We should add features to give programmers more control over
the ownership system, chiefly by allowing the propagation
of "shared" values. This will be an opt-in change; it
will largely consist of annotations and language features
which programmers can simply not use.

- We should add features to allow programmers to express
types with unique ownership, which is to say, types that
cannot be implicitly copied. This will be an opt-in
feature intended for experienced programmers who desire
this level of control; we do not intend for ordinary
Swift programming to require working with such types.

These three tentpoles together have the effect of raising
the ownership system from an implementation detail to a more
visible aspect of the language. They are also somewhat
inseparable, for reasons we'll explain, although of course they
can be prioritized differently. For these reasons, we will
talk about them as a cohensive feature called "ownership".

### A bit more detail

The basic problem with Swift's current ownership system
is copies, and all three tentpoles of ownership are about
avoiding copies.

A value may be used in many different places in a program.
The implementation has to ensure that some copy of the value
survives and is usable at each of these places. As long as
a type is copyable, it's always possible to satisfy that by
making more copies of the value. However, most uses don't
actually require ownership of their own copy. Some do: a
variable that didn't own its current value would only be
able to store values that were known to be owned by something
else, which isn't very useful in general. But a simple thing
like reading a value out of a class instance only requires that
the instance still be valid, not that the code doing the
read actually own a reference to it itself. Sometimes the
difference is obvious, but often it's impossible to know.
For example, the compiler generally doesn't know how an
arbitrary function will use its arguments; it just falls
back on a default rule for whether to pass ownership of
the value. When that default rule is wrong, the program
will end up making extra copies at runtime. So one simple
thing we can do is allow programs to be more explicit at
certain points about whether they need ownership or not.

That closely dovetails with the desire to support non-copyable
types. Most resources require a unique point of destruction:
a memory allocation can only be freed once, a file can only
be closed once, a lock can only be released once, and so on.
An owning reference to such a resource is therefore naturally
unique and thus non-copyable. Of course, we can artificially
allow ownership to be shared by, say, adding a reference count
and only destroying the resource when the count reaches zero.
But this can substantially increase the overhead of working
with the resource; and worse, it introduces problems with
concurrency and re-entrancy. If ownership is unique, and the
language can enforce that certain operations on a resource
can only be performed by the code that owns the resource,
then by construction only one piece of code can perform those
operations at a time. As soon as ownership is shareable,
that property disappears. So it is interesting for the
language to directly support non-copyable types because they
allow the expression of optimally-efficient abstractions
over resources. However, working with such types requires
all of the abstraction points like function arguments to
be correctly annotated about whether they transfer ownership,
because the compiler can no longer just make things work
behind the scenes by adding copies.

Solving either of these problems well will require us to
also solve the problem of non-exclusive access to variables.
Swift today allows nested accesses to the same variable;
for example, a single variable can be passed as two different
`inout` arguments, or a method can be passed a callback that
somehow accesses the same variable that the method was called on.
Doing this is mostly discouraged, but it's not forbidden,
and both the compiler and the standard library have to bend
over backwards to ensure that the program won't misbehave
too badly if it happens. For example, `Array` has to retain
its buffer during an in-place element modification; otherwise,
if that modification somehow reassigned the array variable,
the buffer would be freed while the element was still being
changed. Similarly, the compiler generally finds it difficult
to prove that values in memory are the same at different points
in a function, because it has to assume that any opaque
function call might rewrite all memory; as a result, it
often has to insert copies or preserve redundant loads
out of paranoia. Worse, non-exclusive access greatly
limits the usefulness of explicit annotations. For example,
a "shared" argument is only useful if it's really guaranteed
to stay valid for the entire call, but the only way to
reliably satisfy that for the current value of a variable
that can be re-entrantly modified is to make a copy and pass
that instead. It also makes certain important patterns
impossible, like stealing the current value of a variable
in order to build something new; this is unsound if the
variable can be accessed by other code in the middle.
The only solution to this is to establish a rule that prevents
multiple contexts from accessing the same variable at the
same time. This is what we propose to do with the Law
of Exclusivity.

All three of these goals are closely linked and mutually
reinforcing. The Law of Exclusivity allows explicit annotations
to actually optimize code by default and enables mandatory
idioms for non-copyable types. Explicit annotations create
more optimization opportunities under the Law and enable
non-copyable types to function. Non-copyable types validate
that annotations are optimal even for copyable types and
create more situations where the Law can be satisfied statically.

### Criteria for success

As discussed above, it is the core team's expectation that
ownership can be delivered as an opt-in enhancement to Swift.
Programmers should be able to largely ignore ownership and not
suffer for it. If this expectation proves to not be satisfiable,
we will reject ownership rather than imposing substantial
burdens on regular programs.

The Law of Exclusivity will impose some new static and dynamic
restrictions. It is our belief that these restrictions will only
affect a small amount of code, and only code that does things
that we already document as producing unspecified results.
These restrictions, when enforced dynamically, will also hurt
performance. It is our hope that this will be "paid for" by
the improved optimization potential. We will also provide tools
for programmers to eliminate these safety checks where necessary.
We will discuss these restrictions in greater detail later in this
document.

## Core definitions

### Values

Any discussion of ownership systems is bound to be at a lower
level of abstraction. We will be talking a lot about
implementation topics. In this context, when we say "value",
we mean a specific instance of a semantic, user-language value.

For example, consider the following Swift code:

var x = [1,2,3]
var y = x

People would often say that `x` and `y` have the same value
at this point. Let's call this a *semantic value*. But at
the level of the implementation, because the variables `x` and `y`
can be independently modified, the value in `y` must be a
copy of the value in `x`. Let's call this a *value instance*.
A value instance can be moved around in memory and remain the
same value instance, but a copy always yields a new value instance.
For the remainder of this document, when we use "value" without any
qualification, we mean it in this low-level sense of value instance.

What it means to copy or destroy a value instance depends on the type:

* Some types do not require extra work besides copying their
byte-representation; we call these *trivial*. For example,
`Int` and `Float` are trivial types, as are ordinary `struct`s
and `enum`s containing only such values. Most of what we have
to say about ownership in this document doesn't apply to the
values of such types. However, the Law of Exclusivity will still
apply to them.

* For reference types, the value instance is a reference to an object.
Copying the value instance means making a new reference, which
increases the reference count. Destroying the value instance means
destroying a reference, which decreases the reference count. Decreasing
the reference count can, of course, drop it to zero and thus destroy
the object, but it's important to remember that all this talk about
copying and destroying values means manipulating reference counts,
not copying the object or (necessarily) destroying it.

* For copy-on-write types, the value instance includes a reference to
a buffer, which then works basically like a reference type. Again,
it is important to remember that copying the value doesn't mean
copying the contents of the buffer into a new buffer.

There are similar rules for every kind of type.

### Memory

In general, a value can be owned in one of two ways: it can be
"in flight", a temporary value owned by a specific execution context
which computed the value as an operand, or it can be "at rest",
stored in some sort of memory.

We don't need to focus much on temporary values because their
ownership rules are straightforward. Temporary values are created
as the result of some expression; that expression is used in some
specific place; the value is needed in that place and not
thereafter; so the implementation should clearly take all possible
steps to forward the value directly to that place instead of
forcing it to be copied. Users already expect all of this to
happen, and there's nothing really to improve here.

Therefore, most of our discussion of ownership will center around
values stored in memory. There are five closely related concepts
in Swift's treatment of memory.

A *storage declaration* is the language-syntax concept of a declaration
that can be treated in the language like memory. Currently, these are
always introduced with `let`, `var`, and `subscript`. A storage
declaration has a type. It also has an implementation which defines
what it means to read or write the storage. The default implementation
of a `var` or `let` just creates a new variable to store the value,
but storage declarations can also be computed, and so there needn't
be any variables at all behind one.

A *storage reference expression* is the syntax concept of an expression
that refers to storage. This is similar to the concept from other
languages of an "l-value", except that it isn't necessarily usable on
the left side of an assignment because the storage doesn't have to be
mutable.

A *storage reference* is the language-semantics concept of a fully
filled-in reference to a specific storage declaration. In other
words, it is the result of evaluating a storage reference expression
in the abstract, without actually accessing the storage. If the
storage is a member, this includes a value or storage reference
for the base. If the storage is a subscript, this includes a value
for the index. For example, a storage reference expression like
`widgets[i].weight` might abstractly evaluate to this storage reference:

* the storage for the property `var weight: Double` of
* the storage for the subscript `subscript(index: Int)` at index value `19: Int` of
* the storage for the local variable `var widgets: [Widget]`

A *variable* is the semantics concept of a unique place in
memory that stores a value. It's not necessarily mutable, at least
as we're using it in this document. Variables are usually created for
storage declarations, but they can also be created dynamically in
raw memory, e.g. using UnsafeRawPointer. A variable always has a
specific type. It also has a *lifetime*, i.e. a point in the language
semantics where it comes into existence and a point (or several)
where it is destroyed.

A *memory location* is a contiguous range of addressable memory. In
Swift, this is mostly an implementation concept. Swift does not
guarantee that any particular variable will have a consistent memory
location throughout its lifetime, or in fact be stored in a memory
location at all. But a variable can sometimes be temporarily forced
to exist at a specific, consistent location: e.g. it can be passed
`inout` to `withUnsafeMutablePointer`.

### Accesses

A particular evaluation of a storage reference expression is
called an access. Accesses come in three kinds: *reads*,
*assignments*, and *modifications*. Assignments and modifications
are both *writes*, with the difference being that an assignment
completely replaces the old value without reading it, while a
modification does rely on the old value.

All storage reference expressions are classified into one of these
three kinds of access based on the context in which the expression
appears. It is important to note that this decision is superficial:
it relies only on the semantic rules of the immediate context, not
on a deeper analysis of the program or its dynamic behavior.
For example, a storage reference passed as an `inout` argument
is always evaluated as a modification in the caller, regardless
of whether the callee actually uses the current value, performs
any writes to it, or even refers to it at all.

The evaluation of a storage reference expression is divided into
two phases: it is first formally evaluated to a storage reference,
and then a formal access to that storage reference occurs for some
duration. The two phases are often evaluated in immediate
succession, but they can be separated in complex cases, such as
when an `inout` argument is not the last argument to a call.
The purpose of this phase division is to minimize the duration of
the formal access while still preserving, to the greatest extent
possible, Swift's left-to-right evaluation rules.

## The Law of Exclusivity

With all of that established, we can succinctly state the first
part of this proposal, the Law of Exclusivity:

If a storage reference expression evaluates to a storage
reference that is implemented by a variable, then the formal
access duration of that access may not overlap the formal
access duration of any other access to the same variable
unless both accesses are reads.

This is intentionally vague: it merely says that accesses
"may not" overlap, without specifying how that will be
enforced. This is because we will use different enforcement
mechanisms for different kinds of storage. We will discuss
those mechanisms in the next major section. First, however,
we need to talk in general about some of the implications of
this rule and our approach to satisfying it.

### Duration of exclusivity

The Law says that accesses must be exclusive for their entire
formal access duration. This duration is determined by the
immediate context which causes the access; that is, it's a
*static* property of the program, whereas the safety problems
we laid out in the introduction are *dynamic*. It is a general
truth that static approaches to dynamic problems can only be
conservatively correct: there will be dynamically-reasonable
programs that are nonetheless rejected. It is fair to ask how
that general principle applies here.

For example, when storage is passed as an `inout` argument, the
access lasts for the duration of the call. This demands
caller-side enforcement that no other accesses can occur to
that storage during the call. Is it possible that this is too
coarse-grained? After all, there may be many points within the
called function where it isn't obviously using its `inout`
argument. Perhaps we should track accesses to `inout` arguments
at a finer-grained level, within the callee, instead of attempting
to enforce the Law of Exclusivity in the caller. The problem
is that that idea is simply too dynamic to be efficiently
implemented.

A caller-side rule for `inout` has one key advantage: the
caller has an enormous amount of information about what
storage is being passed. This means that a caller-side rule
can often be enforced purely statically, without adding dynamic
checks or making paranoid assumptions. For example, suppose
that a function calls a `mutating` method on a local variable.
(Recall that `mutating` methods are passed `self` as an `inout`
argument.) Unless the variable has been captured in an
escaping closure, the function can easily examine every
access to the variable to see that none of them overlap
the call, thus proving that the rule is satisfied. Moreover,
that guarantee is then passed down to the callee, which can
use that information to prove the safety of its own accesses.

In contrast, a callee-side rule for `inout` cannot take
advantage of that kind of information: the information is
simply discarded at the point of the call. This leads to the
widespread optimization problems that we see today, as
discussed in the introduction. For example, suppose that
the callee loads a value from its argument, then calls
a function which the optimizer cannot reason about:

extension Array {
 mutating func organize(_ predicate: (Element) -> Bool) {
   let first = self[0]
   if !predicate(first) { return }
   ...
   // something here uses first
 }
}

Under a callee-side rule, the optimizer must copy `self[0]`
into `first` because it must assume (paranoidly) that
`predicate` might somehow turn around and modify the
variable that `self` was bound to. Under a caller-side
rule, the optimizer can use the copy of value held in the
array element for as long as it can continue to prove that
the array hasn't been modified.

Moreover, as the example above suggests, what sort of code
would we actually be enabling by embracing a callee-side rule?
A higher-order operation like this should not have to worry
about the caller passing in a predicate that re-entrantly
modifies the array. Simple implementation choices, like
making the local variable `first` instead of re-accessing
`self[0]` in the example above, would become semantically
important; maintaining any sort of invariant would be almost
inconceivable. It is no surprise that Swift's libraries
generally forbid this kind of re-entrant access. But,
since the library can't completely prevent programmers
from doing it, the implementation must nonetheless do extra
work at runtime to prevent such code from running into
undefined behavior and corrupting the process. Because it
exists solely to work around the possibility of code that
should never occur in a well-written program, we see this
as no real loss.

Therefore, this proposal generally proposes access-duration
rules like caller-side `inout` enforcement, which allow
substantial optimization opportunities at little semantic
cost.

### Components of value and reference types

We've been talking about *variables* a lot. A reader might
reasonably wonder what all this means for *properties*.

Under the definition we laid out above, a property is a
storage declaration, and a stored property creates a
corresponding variable in its container. Accesses to that
variable obviously need to obey the Law of Exclusivity, but are
there any additional restrictions in play due to the fact
that the properties are organized together into a container?
In particular, should the Law of Exclusivity prevent accesses
to different properties of the same variable or value from
overlapping?

Properties can be classified into three groups:
- instance properties of value types,
- instance properties of reference types, and
- `static` and `class` properties on any kind of type.

We propose to always treat reference-type and `static` properties
as independent from one another other, but to treat value-type
properties as generally non-independent outside of a specific
(but important) special case. That's a potentially significant
restriction, and it's reasonable to wonder both why it's necessary
and why we need to draw this distinction between different
kinds of property. There are three reasons.

#### Independence and containers

The first relates to the container.

For value types, it is possible to access both an individual
property and the entire aggregate value. It is clear that an
access to a property can conflict with an access to the aggregate,
because an access to the aggregate is essentially an access to
all of the properties at once. For example, consider a variable
(not necessarily a local one) `p: Point` with stored properties
`x`, `y`, and `z`. If it were possible to simultaneously and
independently modify `p` and `p.x`, that would be an enormous
hole in the Law of Exclusivity. So we do need to enforce the
Law somehow here. We have three options.

(This may make more sense after reading the main section
about enforcing the Law.)

The first option is to simply treat `p.x` as also an access to `p`.
This neatly eliminates the hole because whatever enforcement
we're using for `p` will naturally prevent conflicting accesses
to it. But this will also prevent accesses to different
properties from overlapping, because each will cause an access
to `p`, triggering the enforcement.

The other two options involve reversing that relationship.
We could split enforcement out for all the individual stored
properties, not for the aggregate: an access to `p` would be
treated as an access to `p.x`, `p.y`, and `p.z`. Or we could
parameterize enforcement and teach it to record the specific
path of properties being accessed: "", ".x", and so on.
Unfortunately, there are two problems with these schemes.
The first is that we don't always know the full set of
properties, or which properties are stored; the implementation
of a type might be opaque to us due to e.g. generics or
resilience. An access to a computed property must be treated
as an access to the whole value because it involves passing
the variable to a getter or setter either `inout` or `shared`;
thus it does actually conflict with all other properties.
Attempting to make things work despite that by using dynamic
information would introduce ubiquitous bookkeeping into
value-type accessors, endangering the core design goal of
value types that they serve as a low-cost abstraction tool.
The second is that, while these schemes can be applied to
static enforcement relatively easily, applying them to
dynamic enforcement would require a fiendish amount of
bookkeeping to be carried out dynamically; this is simply
not compatible with our performance goals.

Thus, while there is a scheme which allows independent access
to different properties of the same aggregate value, it
requires us to be using static enforcement for the aggregate
access and to know that both properties are stored. This is an
important special case, but it is just a special case.
In all other cases, we must fall back on the general rule
that an access to a property is also an access to the aggregate.

These considerations do not apply to `static` properties and
properties of reference types. There are no language constructs
in Swift which access every property of a class simultaneously,
and it doesn't even make sense to talk about "every" `static`
property of a type because an arbitrary module can add a new
one at any time.

#### Idioms of independent access

The second relates to user expectations.

Preventing overlapping accesses to different properties of a
value type is at most a minor inconvenience. The Law of Exclusivity
prevents "spooky action at a distance" with value types anyway:
for example, calling a method on a variable cannot kick off a
non-obvious sequence of events which eventually reach back and
modify the original variable, because that would involve two
conflicting and overlapping accesses to the same variable.

In contrast, many established patterns with reference types
depend on exactly that kind of notification-based update. In
fact, it's not uncommon in UI code for different properties of
the same object to be modified concurrently: one by the UI and
the other by some background operation. Preventing independent
access would break those idioms, which is not acceptable.

As for `static` properties, programmers expect them to be
independent global variables; it would make no sense for
an access to one global to prevent access to another.

#### Independence and the optimizer

The third relates to the optimization potential of properties.

Part of the purpose of the Law of Exclusivity is that it
allows a large class of optimizations on values. For example,
a non-`mutating` method on a value type can assume that `self`
remains exactly the same for the duration of the method. It
does not have to worry that an unknown function it calls
in the middle will somehow reach back and modify `self`,
because that modification would violate the Law. Even in a
`mutating` method, no code can access `self` unless the
method knows about it. Those assumptions are extremely
important for optimizing Swift code.

However, these assumptions simply cannot be done in general
for the contents of global variables or reference-type
properties. Class references can be shared arbitrarily,
and the optimizer must assume that an unknown function
might have access to the same instance. And any code in
the system can potentially access a global variable (ignoring
access control). So the language implementation would
gain little to nothing from treating accesses to different
properties as non-independent.

#### Subscripts

Much of this discussion also applies to subscripts, though
in the language today subscripts are never technically stored.
Accessing a component of a value type through a subscript
is treated as accessing the entire value, and so is considered
to overlap any other access to the value. The most important
consequence of this is that two different array elements cannot
be simultaneously accessed. This will interfere with certain
common idioms for working with arrays, although some cases
(like concurrently modifying different slices of an array)
are already quite problematic in Swift. We believe that we
can mitigate the majority of the impact here with targetted
improvements to the collection APIs.

## Enforcing the Law of Exclusivity

There are three available mechanisms for enforcing the Law of
Exclusivity: static, dynamic, and undefined. The choice
of mechanism must be decidable by a simple inspection of the
storage declaration, because the definition and all of its
direct accessors must agree on how it is done. Generally,
it will be decided by the kind of storage being declared,
its container (if any), and any attributes that might be
present.

### Static enforcement

Under static enforcement, the compiler detects that the
law is being violated and reports an error. This is the
preferred mechanism where possible because it is safe, reliable,
and imposes no runtime costs.

This mechanism can only be used when it is perfectly decidable.
For example, it can be used for value-type properties because
the Law, recursively applied, ensures that the base storage is
being exclusively accessed. It cannot be used for ordinary
reference-type properties because there is no way to prove in
general that a particular object reference is the unique
reference to an object. However, if we supported
uniquely-referenced class types, it could be used for their
properties.

In some cases, where desired, the compiler may be able to
preserve source compatibility and avoid an error by implicitly
inserting a copy instead. This likely something we would only
do in a source-compatibility mode.

Static enforcement will be used for:

- immutable variables of all kinds,

- local variables, except as affected by the use of closures
(see below),

- `inout` arguments, and

- instance properties of value types.

### Dynamic enforcement

Under dynamic enforcement, the implementation will maintain
a record of whether each variable is currently being accessed.
If a conflict is detected, it will trigger a dynamic failure.
The compiler may emit an error statically if it detects that
dynamic enforcement will always detect a conflict.

The bookkeeping requires two bits per variable, using a tri-state
of "unaccessed", "read", and "modified". Although multiple
simultaneous reads can be active at once, a full count can be
avoided by saving the old state across the access, with a little
cleverness.

The bookkeeping is intended to be best-effort. It should reliably
detect deterministic violations. It is not required to detect
race conditions; it often will, and that's good, but it's not
required to. It *is* required to successfully handle the case
of concurrent reads without e.g. leaving the bookkeeping record
permanently in the "read" state. But it is acceptable for the
concurrent-reads case to e.g. leave the bookkeeping record in
the "unaccessed" case even if there are still active readers;
this permits the bookkeeping to use non-atomic operations.
However, atomic operations would have to be used if the bookkeeping
records were packed into a single byte for, say, different
properties of a class, because concurrent accesses are
allowed on different variables within a class.

When the compiler detects that an access is "instantaneous",
in the sense that none of the code executed during the access
can possibly cause a re-entrant access to the same variable,
it can avoid updating the bookkeeping record and instead just
check that it has an appropriate value. This is common for
reads, which will often simply copy the value during the access.
When the compiler detects that all possible accesses are
instantaneous, e.g. if the variable is `private` or `internal`,
it can eliminate all bookkeeping. We expect this to be fairly
common.

Dynamic enforcement will be used for:

- local variables, when necessary due to the use of closures
(see below),

- instance properties of class types,

- `static` and `class` properties, and

- global variables.

We should provide an attribute to allow dynamic enforcement
to be downgraded to undefined enforcement for a specific
property or class. It is likely that some clients will find
the performance consequences of dynamic enforcement to be
excessive, and it will be important to provide them an opt-out.
This will be especially true in the early days of the feature,
while we're still exploring implementation alternatives and
haven't yet implemented any holistic optimizations.

Future work on isolating class instances may allow us to
use static enforcement for some class instance properties.

### Undefined enforcement

Undefined enforcement means that conflicts are not detected
either statically or dynamically, and instead simply have
undefined behavior. This is not a desireable mechanism
for ordinary code given Swift's "safe by default" design,
but it's the only real choice for things like unsafe pointers.

Undefined enforcement will be used for:

- the `memory` properties of unsafe pointers.

### Enforcement for local variables captured by closures

Our ability to statically enforce the Law of Exclusivity
relies on our ability to statically reason about where
uses occur. This analysis is usually straightforward for a
local variable, but it becomes complex when the variable is
captured in a closure because the control flow leading to
the use can be obscured. A closure can potentially be
executed re-entrantly or concurrently, even if it's known
not to escape. The following principles apply:

- If a closure `C` potentially escapes, then for any variable
`V` captured by `C`, all accesses to `V` potentially executed
after a potential escape (including the accesses within `C`
itself) must use dynamic enforcement unless all such acesses
are reads.

- If a closure `C` does not escape a function, then its
use sites within the function are known; at each, the closure
is either directly called or used as an argument to another
call. Consider the set of non-escaping closures used at
each such call. For each variable `V` captured by `C`, if
any of those closures contains a write to `V`, all accesses
within those closures must use dynamic enforcement, and
the call is treated for purposes of static enforcement
as if it were a write to `V`; otherwise, the accesses may use
static enforcement, and the call is treated as if it were a
read of `V`.

It is likely that these rules can be improved upon over time.
For example, we should be able to improve on the rule for
direct calls to closures.

## Explicit tools for ownership

### Shared values

A lot of the discussion in this section involves the new concept
of a *shared value*. As the name suggests, a shared value is a
value that has been shared with the current context by another
part of the program that owns it. To be consistent with the
Law of Exclusivity, because multiple parts of the program can
use the value at once, it must be read-only in all of them
(even the owning context). This concept allows programs to
abstract over values without copying them, just like `inout`
allows programs to abstract over variables.

(Readers familiar with Rust will see many similarities between
shared values and Rust's concept of an immutable borrow.)

When the source of a shared value is a storage reference, the
shared value acts essentially like an immutable reference
to that storage. The storage is accessed as a read for the
duration of the shared value, so the Law of Exclusivity
guarantees that no other accesses will be able to modify the
original variable during the access. Some kinds of shared
value may also bind to temporary values (i.e. an r-value).
Since temporary values are always owned by the current
execution context and used in one place, this poses no
additional semantic concerns.

A shared value can be used in the scope that binds it
just like an ordinary parameter or `let` binding.
If the shared value is used in a place that requires
ownership, Swift will simply implicitly copy the value —
again, just like an ordinary parameter or `let` binding.

#### Limitations of shared values

This section of the document describes several ways to form
and use shared values. However, our current design does not
provide general, "first-class" mechanisms for working with them.
A program cannot return a shared value, construct an array
of shared values, store shared values into `struct` fields,
and so on. These limitations are similar to the existing
limitations on `inout` references. In fact, the similarities
are so common that it will be useful to have a term that
encompasses both: we will call them *ephemerals*.

The fact that our design does not attempt to provide first-class
facilities for ephemerals is a well-considered decision,
born from a trio of concerns:

- We have to scope this proposal to something that can
conceivably be implemented in the coming months. We expect this
proposal to yield major benefits to the language and its
implementaton, but it is already quite broad and aggressive.
First-class ephemerals would add enough complexity to the
implementation and design that they are clearly out of scope.
Furthermore, the remaining language-design questions are
quite large; several existing languages have experimented
with first-class ephemerals, and the results haven't been
totally satisfactory.

- Type systems trade complexity for expressivity.
You can always accept more programs by making the type
system more sophisticated, but that's not always a good
trade-off. The lifetime-qualification systems behind
first-class references in languages like Rust add a lot
of complexity to the user model. That complexity has real
costs for users. And it's still inevitably necessary
to sometimes drop down to unsafe code to work around the
limitations of the ownership system. Given that a line
does have to drawn somewhere, it's not completely settled
that lifetime-qualification systems deserve to be on the
Swift side of the line.

- A Rust-like lifetime system would not necessarily be
as powerful in Swift as it is in Rust. Swift intentionally
provides a language model which reserves a lot of
implementation flexibility to both the authors of types
and to the Swift compiler itself.

For example, polymorphic storage is quite a bit more
flexible in Swift than it is in Rust. A
`MutableCollection` in Swift is required to implement a
`subscript` that provides accessor to an element for an index,
but the implementation can satisfy this pretty much any way
it wants. If generic code accesses this `subscript`, and it
happens to be implemented in a way that provides direct access
to the underlying memory, then the access will happen in-place;
but if the `subscript` is implemented with a computed getter
and setter, then the access will happen in a temporary
variable and the getter and setter will be called as necessary.
This only works because Swift's access model is highly
lexical and maintains the ability to run arbitrary code
at the end of an access. Imagine what it would take to
implement a loop that added these temporary mutable
references to an array — each iteration of the loop would
have to be able to queue up arbitrary code to run as a clean-up
when the function was finished with the array. This would
hardly be a low-cost abstraction! A more Rust-like
`MutableCollection` interface that worked within the
lifetime rules would have to promise that the `subscript`
returned a pointer to existing memory; and that wouldn't
allow a computed implementation at all.

A similar problem arises even with simple `struct` members.
The Rust lifetime rules say that, if you have a pointer to
a `struct`, you can make a pointer to a field of that `struct`
and it'll have the same lifetime as the original pointer.
But this assumes not only that the field is actually stored
in memory, but that it is stored *simply*, such that you can
form a simple pointer to it and that pointer will obey the
standard ABI for pointers to that type. This means that
Rust cannot use layout optimizations like packing boolean
fields together in a byte or even just decreasing the
alignment of a field. This is not a guarantee that we are
willing to make in Swift.

For all of these reasons, while we remain theoretically
interested in exploring the possibilities of a more
sophisticated system that would allow broader uses of
ephemerals, we are not proposing to take that on now. Since
such a system would primarily consist of changes to the type
system, we are not concerned that this will cause ABI-stability
problems in the long term. Nor are we concerned that we will
suffer from source incompatibilities; we believe that any
enhancements here can be done as extensions and generalizations
of the proposed features.

### Local ephemeral bindings

It is already a somewhat silly limitation that Swift provides
no way to abstract over storage besides passing it as an
`inout` argument. It's an easy limitation to work around,
since programmers who want a local `inout` binding can simply
introduce a closure and immediately call it, but that's an
awkward way of achieving something that ought to be fairly easy.

Shared values make this limitation even more apparent, because
a local shared value is an interesting alternative to a local `let`:
it avoids a copy at the cost of preventing other accesses to
the original storage. We would not encourage programmers to
use `shared` instead of `let` throughout their code, especially
because the optimizer will often be able to eliminate the copy
anyway. However, the optimizer cannot always remove the copy,
and so the `shared` micro-optimization can be useful in select
cases. Furthermore, eliminating the formal copy may also be
semantically necessary when working with non-copyable types.

We propose to remove this limitation in a straightforward way:

inout root = &tree.root

shared elements = self.queue

The initializer is required and must be a storage reference
expression. The access lasts for the remainder of the scope.

### Function parameters

Function parameters are the most important way in which
programs abstract over values. Swift currently provides
three kinds of argument-passing:

- Pass-by-value, owned. This is the rule for ordinary
arguments. There is no way to spell this explicitly.

- Pass-by-value, shared. This is the rule for the `self`
arguments of `nonmutating` methods. There is no way to
spell this explicitly.

- Pass-by-reference. This is the rule used for `inout`
arguments and the `self` arguments of `mutating` methods.

Our proposal here is just to allow the non-standard
cases to be spelled explicitly:

- A function argument can be explicitly declared `owned`:

 func append(_ values: owned [Element]) {
   ...
 }

This cannot be combined with `shared` or `inout`.

This is just an explicit way of writing the default, and
we do not expect that users will write it often unless
they're working with non-copyable types.

- A function argument can be explicitly declared `shared`.

 func ==(left: shared String, right: shared String) -> Bool {
   ...
 }

This cannot be combined with `owned` or `inout`.

If the function argument is a storage reference expression,
that storage is accessed as a read for the duration of the
call. Otherwise, the argument expression is evaluated as
an r-value and that temporary value is shared for the call.
It's important to allow temporary values to be shared for
function arguments because many function parameters will be
marked as `shared` simply because the functions don't
actually from owning that parameter, not because it's in
any way semantically important that they be passed a
reference to an existing variable. For example, we expect
to change things like comparison operators to take their
parameters `shared`, because it needs to be possible to
compare non-copyable values without claiming them, but
this should not prevent programmers from comparing things
to literal values.

Like `inout`, this is part of the function type. Unlike
`inout`, most function compatibility checks (such as override
and function conversion checking) should succeed with a
`shared` / `owned` mismatch. If a function with an `owned`
parameter is converted to (or overrides) a function with a
`shared` parameter, the argument type must actually be
copyable.

- A method can be explicitly declared `consuming`.

 consuming func moveElements(into collection: inout [Element]) {
   ...
 }

This causes `self` to be passed as an owned value and therefore
cannot be combined with `mutating` or `nonmutating`.

`self` is still an immutable binding within the method.

### Function results

As discussed at the start of this section, Swift's lexical
access model does not extend well to allowing ephemerals
to be returned from functions. Performing an access requires
executing storage-specific code at both the beginning and
the end of the access. After a function returns, it has no
further ability to execute code.

We could, conceivably, return a callback along with the
ephemeral, with the expectation that the callback will be
executed when the caller is done with the ephemeral.
However, this alone would not be enough, because the callee
might be relying on guarantees from its caller. For example,
considering a `mutating` method on a `struct` which wants
to returns an `inout` reference to a stored property. The
correctness of this depends not only on the method being able
to clean up after the access to the property, but on the
continued validity of the variable to which `self` was bound.
What we really want is to maintain the current context in the
callee, along with all the active scopes in the caller, and
simply enter a new nested scope in the caller with the
ephemeral as a sort of argument. But this is a well-understood
situation in programming languages: it is just a kind of
co-routine. (Because of the scoping restrictions, it can
also be thought of as sugar for a callback function in
which `return`, `break`, etc. actually work as expected.)

In fact, co-routines are useful for solving a number of
problems relating to ephemerals. We will explore this
idea in the next few sub-sections.

### `for` loops

In the same sense that there are three interesting ways of
passing an argument, we can identify three interesting styles
of iterating over a sequence. Each of these can be expressed
with a `for` loop.

#### Consuming iteration

The first iteration style is what we're already familiar with
in Swift: a consuming iteration, where each step is presented
with an owned value. This is the only way we can iterate over
an arbitrary sequence where the values might be created on demand.
It is also important for working with collections of non-copyable
types because it allows the collection to be destructured and the
loop to take ownership of the elements. Because it takes ownership
of the values produced by a sequence, and because an arbitrary
sequence cannot be iterated multiple times, this is a
`consuming` operation on `Sequence`.

This can be explicitly requested by declaring the iteration
variable `owned`:

for owned employee in company.employees {
 newCompany.employees.append(employee)
}

It is also used implicitly when the requirements for a
non-mutating iteration are not met. (Among other things,
this is necessary for source compatibility.)

The next two styles make sense only for collections.

#### Non-mutating iteration

A non-mutating iteration simply visits each of the elements
in the collection, leaving it intact and unmodified. We have
no reason to copy the elements; the iteration variable can
simply be bound to a shared value. This is a `nonmutating`
operaton on `Collection`.

This can be explicitly requested by declaring the iteration
variable `shared`:

for shared employee in company.employees {
 if !employee.respected { throw CatastrophicHRFailure() }
}

It is also used by default when the sequence type is known to
conform to `Collection`, since this is the optimal way of
iterating over a collection.

for employee in company.employees {
 if !employee.respected { throw CatastrophicHRFailure() }
}

If the sequence operand is a storage reference expression,
the storage is accessed for the duration of the loop. Note
that this means that the Law of Exclusivity will implicitly
prevent the collection from being modified during the
iteration. Programs can explicitly request an iteration
over a copy of the value in that storage by using the `copy`
intrinsic function on the operand.

#### Mutating iteration

A mutating iteration visits each of the elements and
potentially changes it. The iteration variable is an
`inout` reference to the element. This is a `mutating`
operation on `MutableCollection`.

This must be explicitly requested by declaring the
iteration variable `inout`:

for inout employee in company.employees {
 employee.respected = true
}

The sequence operand must be a storage reference expression.
The storage will be accessed for the duraton of the loop,
which (as above) will prevent any other overlapping accesses
to the collection. (But this rule does not apply if the
collection type defines the operation as a non-mutating
operation, which e.g. a reference-semantics collection might.)

#### Expressing mutating and non-mutating iteration

Mutating and non-mutating iteration require the collection
to produce ephemeral values at each step. There are several
ways we could express this in the language, but one reasonable
approach would be to use co-routines. Since a co-routine does
not abandon its execution context when yielding a value to its
caller, it is reasonable to allow a co-routine to yield
multiple times, which corresponds very well to the basic
code pattern of a loop. This produces a kind of co-routine
often called a generator, which is used in several major
languages to conveniently implement iteration. In Swift,
to follow this pattern, we would need to allow the definition
of generator functions, e.g.:

mutating generator iterateMutable() -> inout Element {
 var i = startIndex, e = endIndex
 while i != e {
   yield &self[i]
   self.formIndex(after: &i)
 }
}

On the client side, it is clear how this could be used to
implement `for` loops; what is less clear is the right way to
allow generators to be used directly by code. There are
interesting constraints on how the co-routine can be used
here because, as mentioned above, the entire co-routine
must logically execute within the scope of an access to the
base value. If, as is common for generators, the generator
function actually returns some sort of generator object,
the compiler must ensure that that object does not escape
that enclosing access. This is a significant source of
complexity.

### Generalized accessors

Swift today provides very coarse tools for implementing
properties and subscripts: essentially, just `get` and `set`
methods. These tools are inadequate for tasks where
performance is critical because they don't allow direct
access to values without copies. The standard library
has access to a slightly broader set of tools which can
provide such direct access in limited cases, but they're
still quite weak, and we've been reluctant to expose them to
users for a variety of reasons.

Ownership offers us an opportunity to revisit this problem
because `get` doesn't work for collections of non-copyable
types because it returns a value, which must therefore be
owned. The accessor really needs to be able to yield a
shared value instead of returning an owned one. Again,
one reasonable approach for allowing this is to use a
special kind of co-routine. Unlike a generator, this
co-routine would be required to yield exactly once.
And there is no need to design an explicit way for programmers
to invoke one because these would only be used in accessors.

The idea is that, instead of defining `get` and `set`,
a storage declaration could define `read` and `modify`:

var x: String
var y: String
var first: String {
 read {
   if x < y { yield x }
   else { yield y }
 }
 modify {
   if x < y { yield &x }
   else { yield &y }
 }
}

A storage declaration must define either a `get` or a `read`
(or be a stored property), but not both.

To be mutable, a storage declaration must also define either a
`set` or a `modify`. It may also choose to define *both*, in
which case `set` will be used for assignments and `modify` will
be used for modifications. This is useful for optimizing
certain complex computed properties because it allows modifications
to be done in-place without forcing simple assignments to first
read the old value; however, care must be taken to ensure that
the `modify` is consistent in behavior with the `get` and the
`set`.

### Intrinsic functions

#### `move`

The Swift optimizer will generally try to move values around
instead of copying them, but it can be useful to force its hand.
For this reason, we propose the `move` function. Conceptually,
`move` is simply a top-level function in the Swift standard
library:

func move<T>(_ value: T) -> T {
 return value
}

However, it is blessed with some special semantics. It cannot
be used indirectly. The argument expression must be a reference
to some kind of local owning storage: either a `let`, a `var`,
or an `inout` binding. A call to `move` is evaluated by
semantically moving the current value out of the argument
variable and returning it as the type of the expression,
leaving the variable uninitialized for the purposes of the
definitive-initialization analysis. What happens with the
variable next depends on the kind of variable:

- A `var` simply transitions back to being uninitialized.
Uses of it are illegal until it is assigned a new value and
thus reinitialized.

- An `inout` binding is just like a `var`, except that it is
illegal for it to go out of scope uninitialized. That is,
if a program moves out of an `inout` binding, the program
must assign a new value to it before it can exit the scope
in any way (including by throwing an error). Note that the
safety of leaving an `inout` temporarily uninitialized
depends on the Law of Exclusivity.

- A `let` cannot be reinitialized and so cannot be used
again at all.

This should be a straightforward addition to the existing
definitive-initialization analysis, which proves that local
variables are initialized before use.

#### `copy`

`copy` is a top-level function in the Swift standard library:

func copy<T>(_ value: T) -> T {
 return value
}

The argument must be a storage reference expression. The
semantics are exactly as given in the above code: the argument
value is returned. This is useful for several reasons:

- It suppresses syntactic special-casing. For example, as
discussed above, if a `shared` argument is a storage
reference, that storage is normally accessed for the duration
of the call. The programmer can suppress this and force the
copy to complete before the call by calling `copy` on the
storage reference before

- It is necessary for types that have suppressed implicit
copies. See the section below on non-copyable types.

#### `endScope`

`endScope` is a top-level function in the Swift standard library:

func endScope<T>(_ value: T) -> () {}

The argument must be a reference to a local `let`, `var`, or
standalone (non-parameter, non-loop) `inout` or `shared`
declaration. If it's a `let` or `var`, the variable is
immediately destroyed. If it's an `inout` or `shared`,
the access immediately ends.

The definitive-initialization analysis must prove that
the declaration is not used after this call. It's an error
if the storage is a `var` that's been captured in an escaping
closure.

This is useful for ending an access before control reaches the
end of a scope, as well as for micro-optimizing the destruction
of values.

`endScope` provides a guarantee that the given variable has
been destroyed, or the given access has ended, by the time
of the execution of the call. It does not promise that these
things happen exactly at that point: the implementation is
still free to end them earlier.

### Lenses

Currently, all storage reference expressions in Swift are *concrete*:
every component is statically resolvable to a storage declaration.
There is some recurring interest in the community in allowing programs
to abstract over storage, so that you might say:

let prop = Widget.weight

and then `prop` would be an abstract reference to the `weight`
property, and its type would be something like `(Widget) -> Double`.

This feature is relevant to the ownership model because an ordinary
function result must be an owned value: not shared, and not mutable.
This means lenses could only be used to abstract *reads*, not
*writes*, and could only be created for copyable properties. It
also means code using lenses would involve more copies than the
equivalent code using concrete storage references.

Suppose that, instead of being simple functions, lenses were their
own type of value. An application of a lens would be a storage
reference expression, but an *abstract* one which accessed
statically-unknown members. This would require the language
implementation to be able to perform that sort of access
dynamically. However, the problem of accessing an unknown
property is very much like the problem of accessing a known
property whose implementation is unknown; that is, the language
already has to do very similar things in order to implement
generics and resilience.

Overall, such a feature would fit in very neatly with the
ownership model laid out here.

## Non-copyable types

Non-copyable types are useful in a variety of expert situations.
For example, they can be used to efficiently express unique
ownership. They are also interesting for expressing values
that have some sort of independent identity, such as atomic
types. They can also be used as a formal mechanism for
encouraging code to work more efficiently with types that
might be expensive to copy, such as large struct types. The
unifying theme is that we do not want to allow the type to
be copied implicitly.

The complexity of handling non-copyable types in Swift
comes from two main sources:

- The language must provide tools for moving values around
and sharing them without forcing copies. We've already
proposed these tools in this document because they're
equally important for optimizing the use of copyable types.

- The generics system has to be able to express generics over
non-copyable types without massively breaking source
compatibility and forcing non-copyable types on everybody.

Otherwise, the feature itself is pretty small. The compiler
implicitly emits moves instead of copies, just like we discussed
above for the `move` intrinsic, and then diagnoses anything
that that didn't work for.

### `moveonly` contexts

The generics problem is real, though. The most obvious way
to model copyability in Swift is to have a `Copyable`
protocol which types can conform to. An unconstrained type
parameter `T` would then not be assumed to be copyable.
Unfortunately, this would be a disaster for both source
compatibility and usability, because almost all the existing
generic code written in Swift assumes copyability, and
we really don't want programmers to have to worry about
non-copyable types in their first introduction to generic
code.

Furthermore, we don't want types to have to explicitly
declare conformance to `Copyable`. That should be the
default.

The logical solution is to maintain the default assumption
that all types are copyable, and then allow select contexts
to turn that assumption off. We will cause these contexts
`moveonly` contexts. All contexts lexically nested within
a `moveonly` context are also implicitly `moveonly`.

A type can be a `moveonly` context:

moveonly struct Array<Element> {
 // Element and Array<Element> are not assumed to be copyable here
}

This suppresses the `Copyable` assumption for the type
declared, its generic arguments (if any), and their
hierarchies of associated types.

An extension can be a `moveonly` context:

moveonly extension Array {
 // Element and Array<Element> are not assumed to be copyable here
}

A type can declare conditional copyability using a conditional
conformance:

moveonly extension Array: Copyable where Element: Copyable {
 ...
}

Conformance to `Copyable`, conditional or not, is an
inherent property of a type and must be declared in the
same module that defines the type. (Or possibly even the
same file.)

A non-`moveonly` extension of a type reintroduces the
copyability assumption for the type and its generic
arguments. This is necessary in order to allow standard
library types to support non-copyable elements without
breaking compatibility with existing extensions. If the
type doesn't declare any conformance to `Copyable`, giving
it a non-`moveonly` extension is an error.

A function can be a `moveonly` context:

extension Array {
 moveonly func report<U>(_ u: U)
}

This suppresses the copyability assumption for any new
generic arguments and their hierarchies of associated types.

A lot of the details of `moveonly` contexts are still up
in the air. It is likely that we will need substantial
implementation experience before we can really settle on
the right design here.

One possibility we're considering is that `moveonly`
contexts will also suppress the implicit copyability
assumption for values of copyable types. This would
provide an important optimization tool for code that
needs to be very careful about copies.

### `deinit` for non-copyable types

A value type declared `moveonly` which does not conform
to `Copyable` (even conditionally) may define a `deinit`
method. `deinit` must be defined in the primary type
definition, not an extension.

`deinit` will be called to destroy the value when it is
no longer required. This permits non-copyable types to be
used to express the unique ownership of resources. For
example, here is a simple file-handle type that ensures
that the handle is closed when the value is destroyed:

moveonly struct File {
 var descriptor: Int32

 init(filename: String) throws {
   descriptor = Darwin.open(filename, O_RDONLY)

   // Abnormally exiting 'init' at any point prevents deinit
   // from being called.
   if descriptor == -1 { throw ... }
 }

 deinit {
   _ = Darwin.close(descriptor)
 }

 consuming func close() throws {
   if Darwin.fsync(descriptor) != 0 { throw ... }

   // This is a consuming function, so it has ownership of self.
   // It doesn't consume self in any other way, so it will
   // destroy it when it exits by calling deinit.  deinit
   // will then handle actually closing the descriptor.
 }
}

Swift is permitted to destroy a value (and thus call `deinit`)
at any time between its last use and its formal point of
destruction. The exact definition of "use" for the purposes
of this definition is not yet fully decided.

If the value type is a `struct`, `self` can only be used
in `deinit` in order to refer to the stored properties
of the type. The stored properties of `self` are treated
like local `let` constants for the purposes of the
definitive-initialization analysis; that is, they are owned
by the `deinit` and can be moved out of.

If the value type is an `enum`, `self` can only be used
in `deinit` as the operand of a `switch`. Within this
`switch`, any associated values are used to initialize
the corresponding bindings, which take ownership of those
values. Such a `switch` leaves `self` uninitialized.

### Explicitly-copyable types

Another idea in the area of non-copyable types that we're
exploring is the ability to declare that a type cannot
be implicitly copied. For example, a very large struct
can formally be copied, but it might be an outsized
impact on performance if it is copied unnecessarily.
Such a type should conform to `Copyable`, and it should
be possible to request a copy with the `copy` function,
but the compiler should diagnose any implicit copies
the same way that it would diagnose copies of a
non-copyable type.

## Implementation priorities

This document has laid out a large amount of work.
We can summarize it as follows:

- Enforcing the Law of Exclusivity:

- Static enforcement
- Dynamic enforcement
- Optimization of dynamic enforcement

- New annotations and declarations:

- `shared` parameters
- `consuming` methods
- Local `shared` and `inout` declarations

- New intrinsics affecting DI:

- The `move` function and its DI implications
- The `endScope` function and its DI implications

- Co-routine features:

- Generalized accessors
- Generators

- Non-copyable types

- Further design work
- DI enforcement
- `moveonly` contexts

The single most important goal for the upcoming releases is
ABI stability. The prioritization and analysis of these
features must center around their impact on the ABI. With
that in mind, here are the primary ABI considerations:

The Law of Exclusivity affects the ABI because it
changes the guarantees made for parameters. We must adopt
this rule before locking down on the ABI, or else we will
get stuck making conservative assumptions forever.
However, the details of how it is enforced do not affect
the ABI unless we choose to offload some of the work to the
runtime, which is not necessary and which can be changed
in future releases. (As a technical note, the Law
of Exclusivity is likely to have a major impact on the
optimizer; but this is an ordinary project-scheduling
consideration, not an ABI-affecting one.)

The standard library is likely to enthusiastically adopt
ownership annotations on parameters. Those annotations will
affect the ABI of those library routines. Library
developers will need time in order to do this adoption,
but more importantly, they will need some way to validate
that their annotations are useful. Unfortunately, the best
way to do that validation is to implement non-copyable types,
which are otherwise very low on the priority list.

The generalized accessors work includes changing the standard
set of "most general" accessors for properties and subscripts
from `get`/`set`/`materializeForSet` to (essentially)
`read`/`set`/`modify`. This affects the basic ABI of
all polymorphic property and subscript accesses, so it
needs to happen. However, this ABI change can be done
without actually taking the step of allowing co-routine-style
accessors to be defined in Swift. The important step is
just ensuring that the ABI we've settled on is good
enough for co-routines in the future.

The generators work may involve changing the core collections
protocols. That will certainly affect the ABI. In contrast
with the generalized accessors, we will absolutely need
to implement generators in order to carry this out.

Non-copyable types and algorithms only affect the ABI
inasmuch as they are adopted in the standard library.
If the library is going to extensively adopt them for
standard collections, that needs to happen before we
stabilize the ABI.

The new local declarations and intrinsics do not affect the ABI.
(As is often the case, the work with the fewest implications
is also some of the easiest.)

Adopting ownership and non-copyable types in the standard
library is likely to be a lot of work, but will be important
for the usability of non-copyable types. It would be very
limiting if it was not possible to create an `Array`
of non-copyable types.

(end)

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Intersec <http://www.intersec.com>
Florent Bruneau | Chief Scientist
E-Mail: florent.bruneau@intersec.com
Mob: +33 (0)6 01 02 65 57
Tour W - 102 Terrasse Boieldieu
92085 Paris La Défense - Cedex France

I ran into this exact issue today. Would something like inout returns help to fix it?

I have a struct called StyledString which gets rid of much of the frustration of dealing with NSAttributedStrings in Swift. Basically, you make selections on the string and set some property of it like so:

  styled.paragraph(2).words(3…7).bold = true

and then at the end, you ask for an attributed string:

  myLabel.attributedText = styled.attributedString

The language I originally designed this for (almost 20 years ago) had a special type of function (called a selector) which could be in the middle of a chain of calls, but not at the end of it… which avoided the problem you are talking about here. In Swift, I basically have a note in the documentation saying not to store the selections in a variable… but that is not ideal.

It would be nice to have a way to say that the return value is not allowed to be stored (only called as part of a chain). This would allow mutable views without the issue of them breaking value semantics.

Thanks,
Jon

···

On Feb 27, 2017, at 9:08 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

3: Mutable Views

Currently a major pain point of Swift has been exposing “mutable views” into a type in a reasonable way. Apologies for length, but here’s an extended example:

  /// Implements a 2D grid (of size fixed upon initialization).
  /// **Not** a `Collection` itself but has many *views* into it that *are* `Collection`s.
  ///
  struct Grid2D<T> {
    // typical CoW backing storage
    fileprivate var storage: Grid2DStorage<T>
    
    /// Obtain a linear traversal of our grid:
    /// - parameter corner: The corner at which we start (e.g. `northWest`)
    /// - parameter motion: The order in which we travel (`latitudeThenLongitude` or `longitudeThanLatitude`)
    ///
    /// - returns: A read-only `Collection` that visits each grid location in `self`, following the requested traversal
    func traversal(from corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T>
  }

…wherein `Grid2DTraversal<T>` is, as noted, a "read-only view” into its parent that also adopts `Collection`.

What would be nice is to be able to make that `Grid2DTraversal<T>` into a mutable view in a way that’s also *safe*; what I mean is something like:

  extension Grid2D {
  
    mutating func mutatingTraversal<T>(from corner: Grid2DCorner, following motion: Grid2DMotion, _ mutator: (inout Grid2DTraversal<T>) -> R) -> R {
      var t = self.traversal(from: corner, following: motion)
      return mutator(&t)
    }

  }

…with the specific goals of (a) having mutations applied via `Grid2DTraversal` get directly written-through to the underlying storage (w/out pointless copying) but also (b) making `Grid2DTraversal` generally act safely in all other contexts.

As it is the “best” way to squeeze this into the type system at this time is arguably:

- define Grid2DTraversal:
  - to have as a strong reference to the backing storage
  - as only having the read-only methods
- *also* define MutableGrid2DTraversal:
  - to have an unowned reference to the backing storage
  - also include the mutating methods

…and then just be careful with API design and patterns of use; in particular only provide access to `MutableGrid2DTraversal<T>` values in the context of closures passed into dedicated functions like `mutatingTraversal`, above…and then just be disciplined never to extract those passed-in values.

Needless to say this isn’t a very satisfactory state of affairs—it is well into “why am I bothering with all this?” territory—and it’d be *far* nicer if the ownership system would allow for `Grid2DTraversal`:

- to adopt `Collection` without restriction
- to adopt `MutableCollection` only in certain ownership contexts
- to have reasonable control over where those contexts apply

It's not sensible to have a type that conditionally conforms to a protocol based on context. However, the requirements of MutableCollection are all 'mutating', so you can't actually use them unless you have a mutable value. So the way to fit what you're asking for into the ownership proposal is to make sure that clients of your view type only have a mutable value when the base was mutable, and the easiest way of getting that is to have the view be vended as storage rather than a return value. If you think about it, a mutable view can't be an independent value anyway, because if code like this could work:

  var grid = ... // note that this is mutable
  var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?
  view.mutate() // reflected in grid, right?

then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.

The proposal suggests doing this instead with storage, so that the view is logically a (mutable) component of the grid. So on the use side:

  var grid = ...
  inout view = &grid[traversingFrom: p, following: m]
  view.mutate()

and on the declaration side:

  struct Grid2D<T> {
    subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {
      read {
        yield Grid2DTraversal(...)
      }
      modify {
        var traversal = Grid2DTraversal(...)
        yield &traversal
        // ensure changes were applied here
      }
    }
  }

If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.

Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is actually part of a larger problem in Swift, which is that we don’t expose enough information to generic code for it to operate safely. This goes back to people asking for a value-equivalent to the “class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
    var _underlying: C

    init(contentsOf other: C) where C: RangeReplaceableCollection {
        _underlying = C();
        _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
    }
}

// Would love to do this…

extension CollectionWrapper {
    init(contentsOf other: C) where C: ValueSemantics {
        _underlying = other
    }
}

As the proposal notes (with the File example), these are semantic considerations which go beyond simple struct/class distinctions: structs may have reference semantics, and classes may have value semantics. Would it be possible to model Copyable/move-only in terms of two new protocols, ValueSemantics and ReferenceSemantics, with trivial types/non-trivial types given appropriate defaults (overridable by the programmer, such as for “File”)?

- Karl

1: Collection Composition

As much as the high-level picture is focused on safety, I’d just like to request a strong focus on making sure the eventual ownership system addresses the common issues like avoiding copies when mutating through optionals, or when nesting collections, and so on.

Avoiding copies is basically the entire core of the proposal. The interaction with safety is that sometimes copies are necessary to avoid memory unsafety, and this proposal recommends an approach that minimizes that.

Thanks for the extend reply and sorry for my own belated reply.

What motivated me to ask for more focus on the common cases was that it was unclear from reading the proposal whether the `inout` binding--as used in `for inout`--could be used with `if`: in other words, we currently have `if let` and `if var`, but will we have `if inout` under this proposal?

I am embarassed to admit I honestly couldn't tell if the proposal didn't contain any examples of `if inout` due to (a) the capability following trivially from the rest of the proposal or (b) the capability falling outside the scope of the proposal.

If it's (a) I apologize and feel free to skip down to the next section, if it's (b) I'll reiterate my request to for more focus on streamlining the common cases. In particular it'd be nice if there was a relatively homogeneous syntax as sketched below:

for related operations starts to diverge a bit:

  var dict: [K:Set<V>] = // ...
  
  // read-only uses `if-let` (or `if shared`?)
  if let setForKey = dict[key] {
    // read `setForKey`
  }
  
  // simple in-place mutation
  if inout setForKey = dict[key] {
    setForKey.mutateSomehow()
  }
  
  // compound "in-place" mutation
  if inout setForKey = dict[key] {
    setForKey.mutateSomehow()
    setForKey.mutateSomeOtherWay()
  }

  // simple "in-place" mutation w/follow-up
  if inout setForKey = dict[key] {
    setForKey.mutateSomehow()
    let shouldRemove = setForKey.isEmpty
    endScope(setForKey)
    if shouldRemove {
      dict.removeValue(forKey: key)
    }
  }

  // compound "in-place" mutation w/follow-up
  if inout setForKey = dict[key] {
    setForKey.mutateSomehow()
    setForKey.mutateSomeOtherWay()
    let shouldRemove = setForKey.isEmpty
    endScope(setForKey)
    if shouldRemove {
      dict.removeValue(forKey: key)
    }
  }
  
...which, again, all use approximately the same syntax for each of these scenarios.

Contrast with what would be the ideal ways to write the above under the proposal AIUI:

  var dict: [K:Set<V>] = // ...
  
  // read-only uses `if-let` (or `if shared`?)
  if let setForKey = dict[key] {
    // read `setForKey`
  }
  
  // simple in-place mutation
  if let index = dict.index(of: key) {
    dict.values[index].mutateSomehow()
  }
  
  // compound "in-place" mutation, I
  // shorter, less-efficent due to repeated lookup
  if let index = dict.index(of: key) {
    dict.values[index].mutateSomehow()
    dict.values[index].mutateSomeOtherWay()
  }

  // compound "in-place" mutation, II
  // longer, more-efficent
  if let index = dict.index(of: key) {
    inout setForKey = &dict.values[index]
    setForKey.mutateSomehow()
    setForKey.mutateSomeOtherWay()
  }

  // simple "in-place" mutation w/follow-up, I
  // longer, less-efficient due to repeated lookup
  if let index = dict.index(of: key) {
    dict.values[index].mutateSomehow()
    if dict.values[index].isEmpty {
      dict.remove(at: index)
    }
  }

  // simple "in-place" mutation w/follow-up, II
  // longer, less-efficient due to repeated lookup
  if let index = dict.index(of: key) {
    inout setForKey = &dict.values[index]
    setForKey.mutateSomehow()
    let shouldRemove = setForKey.isEmpty
    endScope(shouldRemove)
    if shouldRemove {
      dict.remove(at: index)
    }
  }

  // compound "in-place" mutation w/follow-up, I
  // longer, less-efficient due to repeated lookups
  if let index = dict.index(of: key) {
    dict.values[index].mutateSomehow()
    dict.values[index].mutateSomeOtherWay()
    if dict.values[index].isEmpty {
      dict.remove(at: index)
    }
  }

  // compound "in-place" mutation w/follow-up, II
  // longer, less-efficient due to repeated lookup
  if let index = dict.index(of: key) {
    inout setForKey = &dict.values[index]
    setForKey.mutateSomehow()
    setForKey.mutateSomeOtherWay()
    let shouldRemove = setForKey.isEmpty
    endScope(shouldRemove)
    if shouldRemove {
      dict.remove(at: index)
    }
  }

...where my concern is less about what how particular scenario winds up looking and more that there’s such variance *between* the scenarios, at least when compared to a hypothetical `if inout` construct.

Again if `if inout` is actually part of the proposal I apologize for illustrating the consequence of its absence at such length.

The technical obstacle to this is just that, so far, we've tried to make language features like for-loops use formal protocols.

An iteration protocol is going to have requirements like this:
  generator iterate() -> Element
  mutating generator iterateMutable() -> inout Element
But there's no valid substitution that makes '(Key, inout Value)' equal either 'Element' or 'inout Element'. So we'd have to do some special to make this work.

That said, no, there's no intrinsic technical reason this can't be made to work.

The explanation of wanting to stick to formal protocols makes perfect sense. I don’t think this should be a show-stopper, but I do think it’ll be a common request for a subsequent enhancement.

Even in the interim it seems quite feasible to emulate the capability in any concrete case with enough willingness to crank out boilerplate; thus e.g. if someone truly needs `for (index, inout value) in collection.enumerated()` or `for (a, inout b) in zip(as,bs)` it isn’t as if they’re entirely stuck.

3: Mutable Views

It's not sensible to have a type that conditionally conforms to a protocol based on context.

That did indeed seem like a big ask!

I’ll put in an early request to consider

  @moveonly {
    struct File { }
  }

…(or @scope(moveonly) or @context(moveonly) or @dialect(moveonly), etc.).

It’s confusing that `moveonly` essentially applies “inward”—it flags the code *within* a scope as using different assumptions, etc.—in contrast to most of the modifiers like `open`, `final`, `mutating`, etc., apply “outward” (by e.g. describing how visible the code in the scope is from other scopes, etc.).

However, the requirements of MutableCollection are all 'mutating', so you can't actually use them unless you have a mutable value. So the way to fit what you're asking for into the ownership proposal is to make sure that clients of your view type only have a mutable value when the base was mutable, and the easiest way of getting that is to have the view be vended as storage rather than a return value. If you think about it, a mutable view can't be an independent value anyway, because if code like this could work:

  var grid = ... // note that this is mutable
  var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?
  view.mutate() // reflected in grid, right?

then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.

Without belaboring this, the point is indeed to “destroy the value-type properties of `grid`”, while trying to keep things “safe” by quarantining `view`—and the temporary relaxation of value semantics its existence implies—to a specific scope; thus under the status quo the use-site looks like this:

  var grid = // note that this is mutable
  // also note that `mutatingTraversal` is a `mutating` method...
  grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> Void
    in
    // ^ this is the only public method that vends `MutableGrid2DTraversal<T>`, and
    // `MutableGrid2DTraversal<T>` has no public constructors, thus `view` is
    // “quarantined” to this scope unless we actively attempt to leak `view`...
    view.mutate()
  }

…which currently has two major drawbacks:

- (a) lots of code duplication: the immutable `Grid2DTraversal<T>` and the mutable `Mutable2DTraversal<T>`
- (b) the “quarantine” isn’t airtight, in that there are at least these three ways a `view` could escape:

  var grid = // …
  var leakedView: MutatingGrid2DTraversal<T>? = nil
  var otherLeakedView = grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> MutableGrid2DTraversal<T>
    in
    view.mutate()
    // leak #1:
    leakedView = view
    // leak #2:
    self.liveDangerously(leaking: view)
    // leak #3:
    return view
  }

…which imho makes it fair to say “the above approach *encourages* ‘safe’ usage, but can’t *prevent* unsafe usage”.

Under the ownership proposal nothing changes for drawback (a): to stick with the design and behavior sketched above requires distinct types and thus a lot of duplicate or near-duplicate boilerplate.

Drawback (b) seems to fare better under the ownership proposal, provided that I make `MutatingGrid2DTraversal` a non-Copyable type; at least AIUI making `MutatingGrid2DTraversal` non-Copyable would effectively close leaks #1, #2, and #3, b/c:

- I would explicitly have to write e.g. `leakedView = move(view)` (a *very* unlikely accident)
- I would also have to supply a "replacement value” for `view` by the end of the scope (impossible due to lack of public constructors)

…at least if I understand correctly. Is this accurate? If accurate, how likely would it be that “failed to provide replacement value for `view` after move” would get caught at compile time?

Thanks again for providing such detailed clarifications about this proposal.

···

On Feb 27, 2017, at 11:08 AM, John McCall <rjmccall@apple.com> wrote:

On Feb 25, 2017, at 11:41 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The proposal suggests doing this instead with storage, so that the view is logically a (mutable) component of the grid. So on the use side:

  var grid = ...
  inout view = &grid[traversingFrom: p, following: m]
  view.mutate()

and on the declaration side:

  struct Grid2D<T> {
    subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {
      read {
        yield Grid2DTraversal(...)
      }
      modify {
        var traversal = Grid2DTraversal(...)
        yield &traversal
        // ensure changes were applied here
      }
    }
  }

If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.

John.

Anyways, it’s not clear to me, personally, whether or not the above is within the scope of any likely, concrete ownership system that’d follow from the manifesto or not…but if at all possible I’d prefer the eventual ownership system make it reasonable—and reasonably safe—to implement “small-c ‘collection’s that can safely-and-efficiently expose various *mutable* views as big-C `Collection`s”.

Apologies if all of the above considerations have answers that follow trivially from the manifesto; it’s just unclear personally whether the features described in the manifesto would work together to allow something like the above to be implemented more-reasonably than currently the case.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com <mailto:adrian.zubarev@devandartist.com>> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think the idea of dynamic bookkeeping state is pretty great, and, in particular, not having to be exact about the state in the presence of concurrent access is a nice way to make it lightweight.

The way I read the manifesto, the bookkeeping field would work like this:

(a) Thread 1 sets bookkeeping state to read, saves previous state (unaccessed)
(b) Thread 2 sets bookkeeping state to read, saves previous state (read)
(c) Thread 1 ends access, restores state to unacceseed -- too early, but whatever!
(d) Thread 2 ends access, restores state to read? No, you NEVER restore a read.

If you never restore a previously saved "read" state, then you'll never get stuck in a "read" state even if the restore order is wrong (like it is here, because of the multiple threads).

In this scenario, thread 2 could also restore the state to "unaccessed" instead of doing that conditionally on the saved state. In general however, for reentrant functions to keep single-thearded bookkeeping always exact, setting the state to "unaccessed" has to be conditional to the saved state being the same.

If (a) and (b) are not atomic exchanges, a third thread could write a "modify" state during the non-atomic writing of your "read" state, which would make the overlap of the two incompatible accesses undetected.

With atomic exchanges in (a) and (b), an incorrect "modify" can only pass undetected during the time between (c) and (d). If by chance (c) and (d) were to occur in reverse order (making it proper nesting time-wise), an incorrect "modify" between the two would become detectable.

This is all very interesting.

···

Le 17 févr. 2017 à 15:08, John McCall via swift-evolution <swift-evolution@swift.org> a écrit :

We don't have an initial implementation yet, sorry. I'm sure it'll vary a lot by the application. My hope is that it'll just be a few extra non-atomic loads and stores around every access, but it's possible that we'll need to make at least one of those an atomic exchange because it's legal for multiple threads to read concurrently. It hinges in part on how comfortable we are with allowing conflicts to escape dynamic detection in complex concurrent cases.

--
Michel Fortin
https://michelf.ca

Hi John,

This is fantastic! I’ve been eagerly anticipating this. It looks very much as I was hoping it would. I can’t wait to see this vision come to life!

You only show a mutating generator example. Do you also plan to allow shared generators?

Yes; a generator yielding a shared reference would be used for non-mutating iteration.

One topic you don’t touch on that feels related is the ability to use RAII and rely on deferred deinit to ensure an owned resource isn’t released before the scope exits. I can imagine something like `defer let resource = MyResource()`. It may also be interesting to support “defer only” types to force a compiler error where non-deferred use would be incorrect. What do you think?

My intuition is the use cases for this that I'm aware of are really a mis-use of values. You might design an API that way in C++, where destructors are really the only language mechanism for injecting code into a function "later", but in Swift I think you would want to use either (1) a generalized accessor (if the protected resource could meaningfully be described as a single value) or (2) a callback that explicitly scopes what happens with the resource.

So e.g. if you wanted a Rust-style mutex API, you could do it like so:

moveonly struct Locked<T> {
  var unlockedMemory: T { // probably not the best name
    read {
      mutex.acquire()
      defer { mutex.release() } // There are reasons why I think this needs to be in a defer, but we can talk about them when we get to the detailed proposals for co-routines. I'm still looking for a better language design.
      yield actualMemory // Recall that 'read' yields a shared value, so this doesn't implicitly copy.
    }
    nonmutating modify { // 'nonmutating' is a misnomer, but it's an existing misnomer. Setters are 'mutating' methods by default and normally demand exclusive access to self, but we don't need that here because we're dynamically enforcing exclusive access to the memory, so all we need is shared access, and this is how we express that.
      mutex.acquire()
      defer { mutex.release() }
      yield &actualMemory
    }
  }

  private var mutex: Mutex
  private mutable var actualMemory: T // Make this variable mutable even within nonmutating methods; whether that makes sense is the programmer's problem. I didn't cover this in the proposal, because it's speculative, but it's useful for things like our nonmutating modify. Lots of open questions here.
}

I like this approach. It scopes access to the resource as necessary without requiring nesting.

Or if you wanted a more C-like mutex API, you'd do it like so:

moveonly struct Mutex {
  func withLock<T>(_ function: () throws -> T) rethrows -> T {
    acquire()
    defer { release() }
    return try function()
  }
}

But I just don't see the motivation to try to do this by making a function return a C++-style lock guard.

Do you have a use case which clearly benefits from an exact scoping and really needs to be an independent value?

To be honest, I don’t know. The primary thing I am looking for is a way to encapsulate the scoping of a resource without requiring the introduction of a new lexical scope like is required in your second example.

Yes, I agree that the nesting isn't ideal. In particular, it's awkward to get values out of the scope.

The first approach you show above using generalized accessors may well be able to cover our needs. Thanks for taking time to show the example!

Okay, glad to hear it. If you *do* find something which really benefits from an RAII-style value, please let me know; I'm certainly open to the idea.

John.

···

On Feb 20, 2017, at 4:26 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Feb 19, 2017, at 11:24 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Feb 18, 2017, at 11:08 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

John.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com <mailto:adrian.zubarev@devandartist.com>> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think it might not be very related to ownership, but the use of the
word “Copyable” may be a problem. For most programmers when applied to
reference types “Copyable” will connote “Clonable,” i.e. that the
referent (rather than the reference, which is what you're referring to
when you say class types are copyable) can be explicitly copied. So I'm
betting Karl read “Copyable” and was led to this other topic which is of
concern to many people. In that sense, claiming “Copyable” for
ownership without also addressing “Clonable” could be a problem.

The idea behind “Clonable” would be that it gives you a *generic* way to
create a logically *independent* copy of a value, that would work both
for value types and reference types.

···

on Mon Mar 06 2017, John McCall <swift-evolution@swift.org> wrote:

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim-Re5JQEeQqe8AvxtiuMwx3w@public.gane.org> wrote:
Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is

actually part of a larger problem in Swift, which is that we don’t expose enough information to
generic code for it to operate safely. This goes back to people asking for a value-equivalent to the
“class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
    var _underlying: C

    init(contentsOf other: C) where C: RangeReplaceableCollection {
        _underlying = C();
        _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
    }
}

// Would love to do this…

extension CollectionWrapper {
    init(contentsOf other: C) where C: ValueSemantics {
        _underlying = other
    }
}

As the proposal notes (with the File example), these are semantic
considerations which go beyond simple struct/class distinctions:
structs may have reference semantics, and classes may have value
semantics. Would it be possible to model Copyable/move-only in terms
of two new protocols, ValueSemantics and ReferenceSemantics, with
trivial types/non-trivial types given appropriate defaults
(overridable by the programmer, such as for “File”)?

Class types have reference semantics and are still copyable; ownership
is not going to change that. More generally, I don't see how anything
we can do in ownership could ever do something like eliminate the
possibility of a reference-semantics collection from the language.

--
-Dave

Class types have reference semantics and are still copyable; ownership is not going to change that. More generally, I don't see how anything we can do in ownership could ever do something like eliminate the possibility of a reference-semantics collection from the language.

John.

···

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim@gmail.com> wrote:
Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is actually part of a larger problem in Swift, which is that we don’t expose enough information to generic code for it to operate safely. This goes back to people asking for a value-equivalent to the “class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
    var _underlying: C

    init(contentsOf other: C) where C: RangeReplaceableCollection {
        _underlying = C();
        _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
    }
}

// Would love to do this…

extension CollectionWrapper {
    init(contentsOf other: C) where C: ValueSemantics {
        _underlying = other
    }
}

As the proposal notes (with the File example), these are semantic considerations which go beyond simple struct/class distinctions: structs may have reference semantics, and classes may have value semantics. Would it be possible to model Copyable/move-only in terms of two new protocols, ValueSemantics and ReferenceSemantics, with trivial types/non-trivial types given appropriate defaults (overridable by the programmer, such as for “File”)?

That's a very fair point.

John.

···

On Mar 6, 2017, at 4:30 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Mon Mar 06 2017, John McCall <swift-evolution@swift.org> wrote:

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim-Re5JQEeQqe8AvxtiuMwx3w@public.gane.org> wrote:
Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is

actually part of a larger problem in Swift, which is that we don’t expose enough information to
generic code for it to operate safely. This goes back to people asking for a value-equivalent to the
“class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
   var _underlying: C

   init(contentsOf other: C) where C: RangeReplaceableCollection {
       _underlying = C();
       _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
   }
}

// Would love to do this…

extension CollectionWrapper {
   init(contentsOf other: C) where C: ValueSemantics {
       _underlying = other
   }
}

As the proposal notes (with the File example), these are semantic
considerations which go beyond simple struct/class distinctions:
structs may have reference semantics, and classes may have value
semantics. Would it be possible to model Copyable/move-only in terms
of two new protocols, ValueSemantics and ReferenceSemantics, with
trivial types/non-trivial types given appropriate defaults
(overridable by the programmer, such as for “File”)?

Class types have reference semantics and are still copyable; ownership
is not going to change that. More generally, I don't see how anything
we can do in ownership could ever do something like eliminate the
possibility of a reference-semantics collection from the language.

I think it might not be very related to ownership, but the use of the
word “Copyable” may be a problem. For most programmers when applied to
reference types “Copyable” will connote “Clonable,” i.e. that the
referent (rather than the reference, which is what you're referring to
when you say class types are copyable) can be explicitly copied. So I'm
betting Karl read “Copyable” and was led to this other topic which is of
concern to many people. In that sense, claiming “Copyable” for
ownership without also addressing “Clonable” could be a problem.

The idea behind “Clonable” would be that it gives you a *generic* way to
create a logically *independent* copy of a value, that would work both
for value types and reference types.

I'll just drop a note to say that I explained how we could implement provable value-type semantics in the discussion about "pure" a few weeks ago. This was the overview:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170220/032582.html

The part that might have some relation to ownership is the notion in the type system that a pointer is guarantied to be uniquely referenced. You can check for that at runtime with `isUniquelyReferenced`, but that information is lost as soon as the call returns. If there was a way to safely flag a variable as a "unique reference" and for the compiler to detect when the uniqueness might be broken, then it'd open the door to the compiler being able to enforce value-type semantics.

···

On 6 mars 2017, at 15:53, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

Class types have reference semantics and are still copyable; ownership is not going to change that. More generally, I don't see how anything we can do in ownership could ever do something like eliminate the possibility of a reference-semantics collection from the language.

--
Michel Fortin
https://michelf.ca

Part of it is the name; partly I was led there by the examples in the document. For example, a move-only struct with a deinitialiser looks an awful lot like it’s trying to express ReferenceSemantics, since it infers identity. How would using a move-only struct differ from using a class?

I’ve been thinking that we could do with a collection of magic protocols to constrain generic code based on type layout in general. There is a lot of generic code which could benefit from optimised implementations if they know that T is trivial, for example. At a higher level, we often want to know whether a particular type (regardless of struct/class) has reference/value semantics because we care about exclusivity over its contents.

Some of the constraints of the “law of exclusivity” sound like they are providing a kind of value semantic of contents at the variable-level (e.g. shared references are allowed as long as they do not change the contents). Several of the concepts in the document are new to me, but at some broad level there appear to be conceptual similarities.

At the same time, while references to classes are “Copyable” in the ownership sense, those copies are very different from copies of structs. For classes, those copies are basically worthless to the optimiser because it can’t guarantee anything about who else has references to the instance. I’m not really sure classes actually benefit at all from being “Copyable”. Perhaps they should be some other, closely-related thing instead?

- Karl

···

On 6 Mar 2017, at 22:30, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Mon Mar 06 2017, John McCall <swift-evolution@swift.org> wrote:

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim-Re5JQEeQqe8AvxtiuMwx3w@public.gane.org> wrote:
Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is

actually part of a larger problem in Swift, which is that we don’t expose enough information to
generic code for it to operate safely. This goes back to people asking for a value-equivalent to the
“class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
   var _underlying: C

   init(contentsOf other: C) where C: RangeReplaceableCollection {
       _underlying = C();
       _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
   }
}

// Would love to do this…

extension CollectionWrapper {
   init(contentsOf other: C) where C: ValueSemantics {
       _underlying = other
   }
}

As the proposal notes (with the File example), these are semantic
considerations which go beyond simple struct/class distinctions:
structs may have reference semantics, and classes may have value
semantics. Would it be possible to model Copyable/move-only in terms
of two new protocols, ValueSemantics and ReferenceSemantics, with
trivial types/non-trivial types given appropriate defaults
(overridable by the programmer, such as for “File”)?

Class types have reference semantics and are still copyable; ownership
is not going to change that. More generally, I don't see how anything
we can do in ownership could ever do something like eliminate the
possibility of a reference-semantics collection from the language.

I think it might not be very related to ownership, but the use of the
word “Copyable” may be a problem. For most programmers when applied to
reference types “Copyable” will connote “Clonable,” i.e. that the
referent (rather than the reference, which is what you're referring to
when you say class types are copyable) can be explicitly copied. So I'm
betting Karl read “Copyable” and was led to this other topic which is of
concern to many people. In that sense, claiming “Copyable” for
ownership without also addressing “Clonable” could be a problem.

The idea behind “Clonable” would be that it gives you a *generic* way to
create a logically *independent* copy of a value, that would work both
for value types and reference types.

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1: Collection Composition

As much as the high-level picture is focused on safety, I’d just like to request a strong focus on making sure the eventual ownership system addresses the common issues like avoiding copies when mutating through optionals, or when nesting collections, and so on.

Avoiding copies is basically the entire core of the proposal. The interaction with safety is that sometimes copies are necessary to avoid memory unsafety, and this proposal recommends an approach that minimizes that.

Thanks for the extend reply and sorry for my own belated reply.

What motivated me to ask for more focus on the common cases was that it was unclear from reading the proposal whether the `inout` binding--as used in `for inout`--could be used with `if`: in other words, we currently have `if let` and `if var`, but will we have `if inout` under this proposal?

I am embarassed to admit I honestly couldn't tell if the proposal didn't contain any examples of `if inout` due to (a) the capability following trivially from the rest of the proposal or (b) the capability falling outside the scope of the proposal.

I just didn't think about it. "if inout" is quite supportable under the basic model.

The technical obstacle to this is just that, so far, we've tried to make language features like for-loops use formal protocols.

An iteration protocol is going to have requirements like this:
  generator iterate() -> Element
  mutating generator iterateMutable() -> inout Element
But there's no valid substitution that makes '(Key, inout Value)' equal either 'Element' or 'inout Element'. So we'd have to do some special to make this work.

That said, no, there's no intrinsic technical reason this can't be made to work.

The explanation of wanting to stick to formal protocols makes perfect sense. I don’t think this should be a show-stopper, but I do think it’ll be a common request for a subsequent enhancement.

Even in the interim it seems quite feasible to emulate the capability in any concrete case with enough willingness to crank out boilerplate; thus e.g. if someone truly needs `for (index, inout value) in collection.enumerated()` or `for (a, inout b) in zip(as,bs)` it isn’t as if they’re entirely stuck.

I actually spent some more time thinking about it after I wrote it, and there are some nice things that come out of abandoning formal protocols here. You could allow generators to be overloaded, not by name, but by the "inout-shape" of their return value, so that something like
  for (a, inout b) in ...
would specifically look for a generator like:
  generator() -> (T, inout U)
etc.

3: Mutable Views

It's not sensible to have a type that conditionally conforms to a protocol based on context.

That did indeed seem like a big ask!

I’ll put in an early request to consider

  @moveonly {
    struct File { }
  }

…(or @scope(moveonly) or @context(moveonly) or @dialect(moveonly), etc.).

It’s confusing that `moveonly` essentially applies “inward”—it flags the code *within* a scope as using different assumptions, etc.—in contrast to most of the modifiers like `open`, `final`, `mutating`, etc., apply “outward” (by e.g. describing how visible the code in the scope is from other scopes, etc.).

An interesting idea.

However, the requirements of MutableCollection are all 'mutating', so you can't actually use them unless you have a mutable value. So the way to fit what you're asking for into the ownership proposal is to make sure that clients of your view type only have a mutable value when the base was mutable, and the easiest way of getting that is to have the view be vended as storage rather than a return value. If you think about it, a mutable view can't be an independent value anyway, because if code like this could work:

  var grid = ... // note that this is mutable
  var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?
  view.mutate() // reflected in grid, right?

then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.

Without belaboring this, the point is indeed to “destroy the value-type properties of `grid`”, while trying to keep things “safe” by quarantining `view`—and the temporary relaxation of value semantics its existence implies—to a specific scope; thus under the status quo the use-site looks like this:

  var grid = // note that this is mutable
  // also note that `mutatingTraversal` is a `mutating` method...
  grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> Void
    in
    // ^ this is the only public method that vends `MutableGrid2DTraversal<T>`, and
    // `MutableGrid2DTraversal<T>` has no public constructors, thus `view` is
    // “quarantined” to this scope unless we actively attempt to leak `view`...
    view.mutate()
  }

…which currently has two major drawbacks:

- (a) lots of code duplication: the immutable `Grid2DTraversal<T>` and the mutable `Mutable2DTraversal<T>`
- (b) the “quarantine” isn’t airtight, in that there are at least these three ways a `view` could escape:

  var grid = // …
  var leakedView: MutatingGrid2DTraversal<T>? = nil
  var otherLeakedView = grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> MutableGrid2DTraversal<T>
    in
    view.mutate()
    // leak #1:
    leakedView = view
    // leak #2:
    self.liveDangerously(leaking: view)
    // leak #3:
    return view
  }

…which imho makes it fair to say “the above approach *encourages* ‘safe’ usage, but can’t *prevent* unsafe usage”.

Under the ownership proposal nothing changes for drawback (a): to stick with the design and behavior sketched above requires distinct types and thus a lot of duplicate or near-duplicate boilerplate.

Only if you insist that you want a traversal to behave like a linked value even when everything about the traversing code makes it look independent. You're trying to shoe-horn in a kind of reference semantics where it doesn't belong.

Look, your goals are an exact match for the basic ownership design here. You have a type (the grid), it has a thing you can get from it (the traversal), that thing has both mutating and non-mutating operations, you want the mutating operations to be usable if and only if the original value was mutable, you don't want to allow simultaneous accesses to the original value while you have the thing, etc. These are exactly the properties you get by default if starting a traversal is just protecting a component of the value via a property/subscript access. Just accept that a let or var containing a traversal is an independent value.

Drawback (b) seems to fare better under the ownership proposal, provided that I make `MutatingGrid2DTraversal` a non-Copyable type; at least AIUI making `MutatingGrid2DTraversal` non-Copyable would effectively close leaks #1, #2, and #3, b/c:

- I would explicitly have to write e.g. `leakedView = move(view)` (a *very* unlikely accident)
- I would also have to supply a "replacement value” for `view` by the end of the scope (impossible due to lack of public constructors)

…at least if I understand correctly. Is this accurate? If accurate, how likely would it be that “failed to provide replacement value for `view` after move” would get caught at compile time?

It would be guaranteed to get caught at compile time.

This leaking issue is something I didn't get into in the manifesto, but we've actually thought a fair amount about it. Generalized accessors come up a lot in the context of array slices, which share a lot of similar properties with your scenario. With array slices, we have some additional problems:
  - arrays are copy-on-write values, and the original array does need to keep its buffer alive while a slice is being accessed
  - slices need to be usable as independent (and copyable) value types; thus at least sometimes they need to have a strong reference to the buffer
  - forming a mutable slice really shouldn't form a second strong reference to the buffer because then mutations of the slice will trigger a buffer copy
The current line of thinking is that maybe we can have explicit copy and move hooks so that e.g. a projected slice could hold an unowned reference to the buffer which would be promoted to a strong reference on move/copy. But that's a lot of complexity, and I don't think it helps you that much.

Your analysis is correct: making the type move-only solves many of these problems, but not all of them because of the ability to move values aside. Rust has a concept of types that can't even be moved, I think; maybe we need to explore that.

John.

···

On Mar 7, 2017, at 11:47 AM, plx via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 27, 2017, at 11:08 AM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Feb 25, 2017, at 11:41 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Thanks again for providing such detailed clarifications about this proposal.

The proposal suggests doing this instead with storage, so that the view is logically a (mutable) component of the grid. So on the use side:

  var grid = ...
  inout view = &grid[traversingFrom: p, following: m]
  view.mutate()

and on the declaration side:

  struct Grid2D<T> {
    subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {
      read {
        yield Grid2DTraversal(...)
      }
      modify {
        var traversal = Grid2DTraversal(...)
        yield &traversal
        // ensure changes were applied here
      }
    }
  }

If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.

John.

Anyways, it’s not clear to me, personally, whether or not the above is within the scope of any likely, concrete ownership system that’d follow from the manifesto or not…but if at all possible I’d prefer the eventual ownership system make it reasonable—and reasonably safe—to implement “small-c ‘collection’s that can safely-and-efficiently expose various *mutable* views as big-C `Collection`s”.

Apologies if all of the above considerations have answers that follow trivially from the manifesto; it’s just unclear personally whether the features described in the manifesto would work together to allow something like the above to be implemented more-reasonably than currently the case.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com <mailto:adrian.zubarev@devandartist.com>> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi John,

This is fantastic! I’ve been eagerly anticipating this. It looks very much as I was hoping it would. I can’t wait to see this vision come to life!

You only show a mutating generator example. Do you also plan to allow shared generators?

Yes; a generator yielding a shared reference would be used for non-mutating iteration.

One topic you don’t touch on that feels related is the ability to use RAII and rely on deferred deinit to ensure an owned resource isn’t released before the scope exits. I can imagine something like `defer let resource = MyResource()`. It may also be interesting to support “defer only” types to force a compiler error where non-deferred use would be incorrect. What do you think?

My intuition is the use cases for this that I'm aware of are really a mis-use of values. You might design an API that way in C++, where destructors are really the only language mechanism for injecting code into a function "later", but in Swift I think you would want to use either (1) a generalized accessor (if the protected resource could meaningfully be described as a single value) or (2) a callback that explicitly scopes what happens with the resource.

So e.g. if you wanted a Rust-style mutex API, you could do it like so:

moveonly struct Locked<T> {
  var unlockedMemory: T { // probably not the best name
    read {
      mutex.acquire()
      defer { mutex.release() } // There are reasons why I think this needs to be in a defer, but we can talk about them when we get to the detailed proposals for co-routines. I'm still looking for a better language design.
      yield actualMemory // Recall that 'read' yields a shared value, so this doesn't implicitly copy.
    }
    nonmutating modify { // 'nonmutating' is a misnomer, but it's an existing misnomer. Setters are 'mutating' methods by default and normally demand exclusive access to self, but we don't need that here because we're dynamically enforcing exclusive access to the memory, so all we need is shared access, and this is how we express that.
      mutex.acquire()
      defer { mutex.release() }
      yield &actualMemory
    }
  }

  private var mutex: Mutex
  private mutable var actualMemory: T // Make this variable mutable even within nonmutating methods; whether that makes sense is the programmer's problem. I didn't cover this in the proposal, because it's speculative, but it's useful for things like our nonmutating modify. Lots of open questions here.
}

I like this approach. It scopes access to the resource as necessary without requiring nesting.

Or if you wanted a more C-like mutex API, you'd do it like so:

moveonly struct Mutex {
  func withLock<T>(_ function: () throws -> T) rethrows -> T {
    acquire()
    defer { release() }
    return try function()
  }
}

But I just don't see the motivation to try to do this by making a function return a C++-style lock guard.

Do you have a use case which clearly benefits from an exact scoping and really needs to be an independent value?

To be honest, I don’t know. The primary thing I am looking for is a way to encapsulate the scoping of a resource without requiring the introduction of a new lexical scope like is required in your second example.

Yes, I agree that the nesting isn't ideal. In particular, it's awkward to get values out of the scope.

The first approach you show above using generalized accessors may well be able to cover our needs. Thanks for taking time to show the example!

Okay, glad to hear it. If you *do* find something which really benefits from an RAII-style value, please let me know; I'm certainly open to the idea.

Will do. I’ll keep this in the back of my mind and we’ll see if anything bubbles to the surface! :)

···

On Feb 20, 2017, at 3:38 PM, John McCall <rjmccall@apple.com> wrote:

On Feb 20, 2017, at 4:26 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Feb 19, 2017, at 11:24 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Feb 18, 2017, at 11:08 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

John.

John.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com <mailto:adrian.zubarev@devandartist.com>> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is

actually part of a larger problem in Swift, which is that we don’t expose enough information to
generic code for it to operate safely. This goes back to people asking for a value-equivalent to the
“class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
   var _underlying: C

   init(contentsOf other: C) where C: RangeReplaceableCollection {
       _underlying = C();
       _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
   }
}

// Would love to do this…

extension CollectionWrapper {
   init(contentsOf other: C) where C: ValueSemantics {
       _underlying = other
   }
}

As the proposal notes (with the File example), these are semantic
considerations which go beyond simple struct/class distinctions:
structs may have reference semantics, and classes may have value
semantics. Would it be possible to model Copyable/move-only in terms
of two new protocols, ValueSemantics and ReferenceSemantics, with
trivial types/non-trivial types given appropriate defaults
(overridable by the programmer, such as for “File”)?

Class types have reference semantics and are still copyable; ownership
is not going to change that. More generally, I don't see how anything
we can do in ownership could ever do something like eliminate the
possibility of a reference-semantics collection from the language.

I think it might not be very related to ownership, but the use of the
word “Copyable” may be a problem. For most programmers when applied to
reference types “Copyable” will connote “Clonable,” i.e. that the
referent (rather than the reference, which is what you're referring to
when you say class types are copyable) can be explicitly copied. So I'm
betting Karl read “Copyable” and was led to this other topic which is of
concern to many people. In that sense, claiming “Copyable” for
ownership without also addressing “Clonable” could be a problem.

The idea behind “Clonable” would be that it gives you a *generic* way to
create a logically *independent* copy of a value, that would work both
for value types and reference types.

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Part of it is the name; partly I was led there by the examples in the
document. For example, a move-only struct with a deinitialiser looks
an awful lot like it’s trying to express ReferenceSemantics, since it
infers identity. How would using a move-only struct differ from using
a class?

The distinction between value and reference semantics lies in what
happens when you copy or assign, and then mutate. You can't observe
that distinction with move-only types because they have no copy or
assignment. Similarly, you can't observe the difference between value
and reference types when types are immutable. Both immutable and
move-only types eliminate half of the operations you need to be able to
see the distinction.

The confusion about identity occurs because Swift (like most OOP
languages these days) tries hard to erase your ability to see the
difference between the reference and the thing it refers to. References
(what John refers to as Class types above) don't have identity, but the
instances they refer to do. So in that sense, move-only instances are
like class instances.

I’ve been thinking that we could do with a collection of magic
protocols to constrain generic code based on type layout in
general. There is a lot of generic code which could benefit from
optimised implementations if they know that T is trivial, for
example. At a higher level, we often want to know whether a particular
type (regardless of struct/class) has reference/value semantics
because we care about exclusivity over its contents.

Some of the constraints of the “law of exclusivity” sound like they
are providing a kind of value semantic of contents at the
variable-level (e.g. shared references are allowed as long as they do
not change the contents). Several of the concepts in the document are
new to me, but at some broad level there appear to be conceptual
similarities.

At the same time, while references to classes are “Copyable” in the
ownership sense, those copies are very different from copies of
structs. For classes, those copies are basically worthless to the
optimiser because it can’t guarantee anything about who else has
references to the instance.

Except when it can, but yeah, it's harder.

I’m not really sure classes actually benefit at all from being
“Copyable”. Perhaps they should be some other, closely-related thing
instead?

Class references have to be “Copyable” or the world falls apart :-)

···

on Mon Mar 06 2017, Karl Wagner <razielim-AT-gmail.com> wrote:

On 6 Mar 2017, at 22:30, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Mon Mar 06 2017, John McCall <swift-evolution@swift.org> wrote:

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim-Re5JQEeQqe8AvxtiuMwx3w@public.gane.org> wrote:

--
-Dave

1 Like

To put this in code:

magic-protocol HasReferenceSemantics { func retain() }
magic-protocol MoveOnly: HasReferenceSemantics {}

magic-protocol HasValueSemantics {}
magic-protocol Copyable: HasValueSemantics { func copy() -> Self }

extension MoveOnly {
mutating func move() -> Self {
    defer { self.deinitialise() }
    return self
}
}

imaginary-struct Reference<To: HasReferenceSemantics>: HasValueSemantics {
    let referencedThing: To

    init(_ p: inout To) where To: MoveOnly {
        referencedThing = p.move()
    }
    init(_ p: To) {
        p.retain()
        referencedThing = p
    }
    func copy() -> Self {
       referencedThing.retain()
       return self
    }
}

imaginary-class Shared<Thing: HasValueSemanics>: HasReferenceSemantics {
    let sharedThing: Thing
    func retain() { /* no-op */ }
}

That’s basically my understanding from the document. Is that more-or-less correct?

- Karl

···

On 7 Mar 2017, at 02:12, Karl Wagner <karl.swift@springsup.com> wrote:

On 6 Mar 2017, at 22:30, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Mon Mar 06 2017, John McCall <swift-evolution@swift.org> wrote:

On Mar 6, 2017, at 3:46 PM, Karl Wagner <razielim-Re5JQEeQqe8AvxtiuMwx3w@public.gane.org> wrote:
Thanks very much for writing this up, it’s very interesting.

The one thing which I think needs improvement is the Copyable protocol. I think that this is

actually part of a larger problem in Swift, which is that we don’t expose enough information to
generic code for it to operate safely. This goes back to people asking for a value-equivalent to the
“class” or “AnyObject” magic protocols.

For example, often you would like to wrap a Collection and keep some information about what it contains. In order to do that generically, you need to ensure a client can hand you an exclusive view of a collection’s contents, so you know they will not mutate underneath your feet.

Currently, that means you need a RangeReplaceableCollection because it includes an empty initialiser which allows you to create a unique copy of the Collection’s contents. It’s a workaround, but it means we have this unnecessary protocol requirement in the standard library, and in the implementation, which is making copies that may not be required. If my CollectionWrapper is initialised with something which has ValueSemantics, I don’t need to create a whole new instance with equal contents to ensure exclusivity of those contents. If this was an Array, for example, I could simply assign it and it would ensure the underlying contiguous buffer is never mutated.

struct CollectionWrapper<C: Collection> {
  var _underlying: C

  init(contentsOf other: C) where C: RangeReplaceableCollection {
      _underlying = C();
      _underlying.replaceSubrange(_underlying.startIndex..<_underlying.endIndex, with: other)
  }
}

// Would love to do this…

extension CollectionWrapper {
  init(contentsOf other: C) where C: ValueSemantics {
      _underlying = other
  }
}

As the proposal notes (with the File example), these are semantic
considerations which go beyond simple struct/class distinctions:
structs may have reference semantics, and classes may have value
semantics. Would it be possible to model Copyable/move-only in terms
of two new protocols, ValueSemantics and ReferenceSemantics, with
trivial types/non-trivial types given appropriate defaults
(overridable by the programmer, such as for “File”)?

Class types have reference semantics and are still copyable; ownership
is not going to change that. More generally, I don't see how anything
we can do in ownership could ever do something like eliminate the
possibility of a reference-semantics collection from the language.

I think it might not be very related to ownership, but the use of the
word “Copyable” may be a problem. For most programmers when applied to
reference types “Copyable” will connote “Clonable,” i.e. that the
referent (rather than the reference, which is what you're referring to
when you say class types are copyable) can be explicitly copied. So I'm
betting Karl read “Copyable” and was led to this other topic which is of
concern to many people. In that sense, claiming “Copyable” for
ownership without also addressing “Clonable” could be a problem.

The idea behind “Clonable” would be that it gives you a *generic* way to
create a logically *independent* copy of a value, that would work both
for value types and reference types.

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Part of it is the name; partly I was led there by the examples in the document. For example, a move-only struct with a deinitialiser looks an awful lot like it’s trying to express ReferenceSemantics, since it infers identity. How would using a move-only struct differ from using a class?

I’ve been thinking that we could do with a collection of magic protocols to constrain generic code based on type layout in general. There is a lot of generic code which could benefit from optimised implementations if they know that T is trivial, for example. At a higher level, we often want to know whether a particular type (regardless of struct/class) has reference/value semantics because we care about exclusivity over its contents.

Some of the constraints of the “law of exclusivity” sound like they are providing a kind of value semantic of contents at the variable-level (e.g. shared references are allowed as long as they do not change the contents). Several of the concepts in the document are new to me, but at some broad level there appear to be conceptual similarities.

At the same time, while references to classes are “Copyable” in the ownership sense, those copies are very different from copies of structs. For classes, those copies are basically worthless to the optimiser because it can’t guarantee anything about who else has references to the instance. I’m not really sure classes actually benefit at all from being “Copyable”. Perhaps they should be some other, closely-related thing instead?

- Karl

1: Collection Composition

As much as the high-level picture is focused on safety, I’d just like to request a strong focus on making sure the eventual ownership system addresses the common issues like avoiding copies when mutating through optionals, or when nesting collections, and so on.

Avoiding copies is basically the entire core of the proposal. The interaction with safety is that sometimes copies are necessary to avoid memory unsafety, and this proposal recommends an approach that minimizes that.

Thanks for the extend reply and sorry for my own belated reply.

What motivated me to ask for more focus on the common cases was that it was unclear from reading the proposal whether the `inout` binding--as used in `for inout`--could be used with `if`: in other words, we currently have `if let` and `if var`, but will we have `if inout` under this proposal?

I am embarassed to admit I honestly couldn't tell if the proposal didn't contain any examples of `if inout` due to (a) the capability following trivially from the rest of the proposal or (b) the capability falling outside the scope of the proposal.

I just didn't think about it. "if inout" is quite supportable under the basic model.

The technical obstacle to this is just that, so far, we've tried to make language features like for-loops use formal protocols.

An iteration protocol is going to have requirements like this:
  generator iterate() -> Element
  mutating generator iterateMutable() -> inout Element
But there's no valid substitution that makes '(Key, inout Value)' equal either 'Element' or 'inout Element'. So we'd have to do some special to make this work.

That said, no, there's no intrinsic technical reason this can't be made to work.

The explanation of wanting to stick to formal protocols makes perfect sense. I don’t think this should be a show-stopper, but I do think it’ll be a common request for a subsequent enhancement.

Even in the interim it seems quite feasible to emulate the capability in any concrete case with enough willingness to crank out boilerplate; thus e.g. if someone truly needs `for (index, inout value) in collection.enumerated()` or `for (a, inout b) in zip(as,bs)` it isn’t as if they’re entirely stuck.

I actually spent some more time thinking about it after I wrote it, and there are some nice things that come out of abandoning formal protocols here. You could allow generators to be overloaded, not by name, but by the "inout-shape" of their return value, so that something like
  for (a, inout b) in ...
would specifically look for a generator like:
  generator() -> (T, inout U)
etc.

Would it be valid write:

var iter = foo.makeIterator()
inout x = iter.next()

If not, are special case `inout` returns really the right way to model this feature? It seems that a inout-map interface would be better as it doesn't require any special case language features.

Or am I misunderstanding, and `inout` reruns in the general case are supported by this proposal? If so, `inout` seems like a poor name.

···

On Mar 7, 2017, at 10:02 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 7, 2017, at 11:47 AM, plx via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 27, 2017, at 11:08 AM, John McCall <rjmccall@apple.com> wrote:
On Feb 25, 2017, at 11:41 AM, plx via swift-evolution <swift-evolution@swift.org> wrote:

3: Mutable Views

It's not sensible to have a type that conditionally conforms to a protocol based on context.

That did indeed seem like a big ask!

I’ll put in an early request to consider

  @moveonly {
    struct File { }
  }

…(or @scope(moveonly) or @context(moveonly) or @dialect(moveonly), etc.).

It’s confusing that `moveonly` essentially applies “inward”—it flags the code *within* a scope as using different assumptions, etc.—in contrast to most of the modifiers like `open`, `final`, `mutating`, etc., apply “outward” (by e.g. describing how visible the code in the scope is from other scopes, etc.).

An interesting idea.

However, the requirements of MutableCollection are all 'mutating', so you can't actually use them unless you have a mutable value. So the way to fit what you're asking for into the ownership proposal is to make sure that clients of your view type only have a mutable value when the base was mutable, and the easiest way of getting that is to have the view be vended as storage rather than a return value. If you think about it, a mutable view can't be an independent value anyway, because if code like this could work:

  var grid = ... // note that this is mutable
  var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?
  view.mutate() // reflected in grid, right?

then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.

Without belaboring this, the point is indeed to “destroy the value-type properties of `grid`”, while trying to keep things “safe” by quarantining `view`—and the temporary relaxation of value semantics its existence implies—to a specific scope; thus under the status quo the use-site looks like this:

  var grid = // note that this is mutable
  // also note that `mutatingTraversal` is a `mutating` method...
  grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> Void
    in
    // ^ this is the only public method that vends `MutableGrid2DTraversal<T>`, and
    // `MutableGrid2DTraversal<T>` has no public constructors, thus `view` is
    // “quarantined” to this scope unless we actively attempt to leak `view`...
    view.mutate()
  }

…which currently has two major drawbacks:

- (a) lots of code duplication: the immutable `Grid2DTraversal<T>` and the mutable `Mutable2DTraversal<T>`
- (b) the “quarantine” isn’t airtight, in that there are at least these three ways a `view` could escape:

  var grid = // …
  var leakedView: MutatingGrid2DTraversal<T>? = nil
  var otherLeakedView = grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> MutableGrid2DTraversal<T>
    in
    view.mutate()
    // leak #1:
    leakedView = view
    // leak #2:
    self.liveDangerously(leaking: view)
    // leak #3:
    return view
  }

…which imho makes it fair to say “the above approach *encourages* ‘safe’ usage, but can’t *prevent* unsafe usage”.

Under the ownership proposal nothing changes for drawback (a): to stick with the design and behavior sketched above requires distinct types and thus a lot of duplicate or near-duplicate boilerplate.

Only if you insist that you want a traversal to behave like a linked value even when everything about the traversing code makes it look independent. You're trying to shoe-horn in a kind of reference semantics where it doesn't belong.

Look, your goals are an exact match for the basic ownership design here. You have a type (the grid), it has a thing you can get from it (the traversal), that thing has both mutating and non-mutating operations, you want the mutating operations to be usable if and only if the original value was mutable, you don't want to allow simultaneous accesses to the original value while you have the thing, etc. These are exactly the properties you get by default if starting a traversal is just protecting a component of the value via a property/subscript access. Just accept that a let or var containing a traversal is an independent value.

Drawback (b) seems to fare better under the ownership proposal, provided that I make `MutatingGrid2DTraversal` a non-Copyable type; at least AIUI making `MutatingGrid2DTraversal` non-Copyable would effectively close leaks #1, #2, and #3, b/c:

- I would explicitly have to write e.g. `leakedView = move(view)` (a *very* unlikely accident)
- I would also have to supply a "replacement value” for `view` by the end of the scope (impossible due to lack of public constructors)

…at least if I understand correctly. Is this accurate? If accurate, how likely would it be that “failed to provide replacement value for `view` after move” would get caught at compile time?

It would be guaranteed to get caught at compile time.

This leaking issue is something I didn't get into in the manifesto, but we've actually thought a fair amount about it. Generalized accessors come up a lot in the context of array slices, which share a lot of similar properties with your scenario. With array slices, we have some additional problems:
  - arrays are copy-on-write values, and the original array does need to keep its buffer alive while a slice is being accessed
  - slices need to be usable as independent (and copyable) value types; thus at least sometimes they need to have a strong reference to the buffer
  - forming a mutable slice really shouldn't form a second strong reference to the buffer because then mutations of the slice will trigger a buffer copy
The current line of thinking is that maybe we can have explicit copy and move hooks so that e.g. a projected slice could hold an unowned reference to the buffer which would be promoted to a strong reference on move/copy. But that's a lot of complexity, and I don't think it helps you that much.

Your analysis is correct: making the type move-only solves many of these problems, but not all of them because of the ability to move values aside. Rust has a concept of types that can't even be moved, I think; maybe we need to explore that.

John.

Thanks again for providing such detailed clarifications about this proposal.

The proposal suggests doing this instead with storage, so that the view is logically a (mutable) component of the grid. So on the use side:

  var grid = ...
  inout view = &grid[traversingFrom: p, following: m]
  view.mutate()

and on the declaration side:

  struct Grid2D<T> {
    subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {
      read {
        yield Grid2DTraversal(...)
      }
      modify {
        var traversal = Grid2DTraversal(...)
        yield &traversal
        // ensure changes were applied here
      }
    }
  }

If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.

John.

Anyways, it’s not clear to me, personally, whether or not the above is within the scope of any likely, concrete ownership system that’d follow from the manifesto or not…but if at all possible I’d prefer the eventual ownership system make it reasonable—and reasonably safe—to implement “small-c ‘collection’s that can safely-and-efficiently expose various *mutable* views as big-C `Collection`s”.

Apologies if all of the above considerations have answers that follow trivially from the manifesto; it’s just unclear personally whether the features described in the manifesto would work together to allow something like the above to be implemented more-reasonably than currently the case.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1: Collection Composition

As much as the high-level picture is focused on safety, I’d just like to request a strong focus on making sure the eventual ownership system addresses the common issues like avoiding copies when mutating through optionals, or when nesting collections, and so on.

Avoiding copies is basically the entire core of the proposal. The interaction with safety is that sometimes copies are necessary to avoid memory unsafety, and this proposal recommends an approach that minimizes that.

Thanks for the extend reply and sorry for my own belated reply.

What motivated me to ask for more focus on the common cases was that it was unclear from reading the proposal whether the `inout` binding--as used in `for inout`--could be used with `if`: in other words, we currently have `if let` and `if var`, but will we have `if inout` under this proposal?

I am embarassed to admit I honestly couldn't tell if the proposal didn't contain any examples of `if inout` due to (a) the capability following trivially from the rest of the proposal or (b) the capability falling outside the scope of the proposal.

I just didn't think about it. "if inout" is quite supportable under the basic model.

The technical obstacle to this is just that, so far, we've tried to make language features like for-loops use formal protocols.

An iteration protocol is going to have requirements like this:
  generator iterate() -> Element
  mutating generator iterateMutable() -> inout Element
But there's no valid substitution that makes '(Key, inout Value)' equal either 'Element' or 'inout Element'. So we'd have to do some special to make this work.

That said, no, there's no intrinsic technical reason this can't be made to work.

The explanation of wanting to stick to formal protocols makes perfect sense. I don’t think this should be a show-stopper, but I do think it’ll be a common request for a subsequent enhancement.

Even in the interim it seems quite feasible to emulate the capability in any concrete case with enough willingness to crank out boilerplate; thus e.g. if someone truly needs `for (index, inout value) in collection.enumerated()` or `for (a, inout b) in zip(as,bs)` it isn’t as if they’re entirely stuck.

I actually spent some more time thinking about it after I wrote it, and there are some nice things that come out of abandoning formal protocols here. You could allow generators to be overloaded, not by name, but by the "inout-shape" of their return value, so that something like
  for (a, inout b) in ...
would specifically look for a generator like:
  generator() -> (T, inout U)
etc.

Would it be valid write:

var iter = foo.makeIterator()
inout x = iter.next()

If not, are special case `inout` returns really the right way to model this feature? It seems that a inout-map interface would be better as it doesn't require any special case language features.

Or am I misunderstanding, and `inout` reruns in the general case are supported by this proposal? If so, `inout` seems like a poor name.

inout returns are not supported, for reasons covered at length in the manifesto. The specific sub-proposal for for loops is to base them around co-routines, for which inouts would be supported, and for which the "inout" name is somewhat more appropriate (because, you might say, exclusive access to the value in the variable yielded inout is temporarily passed into the caller of the co-routine and then back out to the co-routine). Co-routine yields are quite different from returns in a number of ways.

John.

···

On Mar 7, 2017, at 1:28 PM, jaden.geller@gmail.com wrote:
On Mar 7, 2017, at 10:02 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 7, 2017, at 11:47 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 27, 2017, at 11:08 AM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Feb 25, 2017, at 11:41 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

3: Mutable Views

It's not sensible to have a type that conditionally conforms to a protocol based on context.

That did indeed seem like a big ask!

I’ll put in an early request to consider

  @moveonly {
    struct File { }
  }

…(or @scope(moveonly) or @context(moveonly) or @dialect(moveonly), etc.).

It’s confusing that `moveonly` essentially applies “inward”—it flags the code *within* a scope as using different assumptions, etc.—in contrast to most of the modifiers like `open`, `final`, `mutating`, etc., apply “outward” (by e.g. describing how visible the code in the scope is from other scopes, etc.).

An interesting idea.

However, the requirements of MutableCollection are all 'mutating', so you can't actually use them unless you have a mutable value. So the way to fit what you're asking for into the ownership proposal is to make sure that clients of your view type only have a mutable value when the base was mutable, and the easiest way of getting that is to have the view be vended as storage rather than a return value. If you think about it, a mutable view can't be an independent value anyway, because if code like this could work:

  var grid = ... // note that this is mutable
  var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?
  view.mutate() // reflected in grid, right?

then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.

Without belaboring this, the point is indeed to “destroy the value-type properties of `grid`”, while trying to keep things “safe” by quarantining `view`—and the temporary relaxation of value semantics its existence implies—to a specific scope; thus under the status quo the use-site looks like this:

  var grid = // note that this is mutable
  // also note that `mutatingTraversal` is a `mutating` method...
  grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> Void
    in
    // ^ this is the only public method that vends `MutableGrid2DTraversal<T>`, and
    // `MutableGrid2DTraversal<T>` has no public constructors, thus `view` is
    // “quarantined” to this scope unless we actively attempt to leak `view`...
    view.mutate()
  }

…which currently has two major drawbacks:

- (a) lots of code duplication: the immutable `Grid2DTraversal<T>` and the mutable `Mutable2DTraversal<T>`
- (b) the “quarantine” isn’t airtight, in that there are at least these three ways a `view` could escape:

  var grid = // …
  var leakedView: MutatingGrid2DTraversal<T>? = nil
  var otherLeakedView = grid.mutatingTraversal(from: c, following: m) {
    (inout view: MutableGrid2DTraversal<T>) -> MutableGrid2DTraversal<T>
    in
    view.mutate()
    // leak #1:
    leakedView = view
    // leak #2:
    self.liveDangerously(leaking: view)
    // leak #3:
    return view
  }

…which imho makes it fair to say “the above approach *encourages* ‘safe’ usage, but can’t *prevent* unsafe usage”.

Under the ownership proposal nothing changes for drawback (a): to stick with the design and behavior sketched above requires distinct types and thus a lot of duplicate or near-duplicate boilerplate.

Only if you insist that you want a traversal to behave like a linked value even when everything about the traversing code makes it look independent. You're trying to shoe-horn in a kind of reference semantics where it doesn't belong.

Look, your goals are an exact match for the basic ownership design here. You have a type (the grid), it has a thing you can get from it (the traversal), that thing has both mutating and non-mutating operations, you want the mutating operations to be usable if and only if the original value was mutable, you don't want to allow simultaneous accesses to the original value while you have the thing, etc. These are exactly the properties you get by default if starting a traversal is just protecting a component of the value via a property/subscript access. Just accept that a let or var containing a traversal is an independent value.

Drawback (b) seems to fare better under the ownership proposal, provided that I make `MutatingGrid2DTraversal` a non-Copyable type; at least AIUI making `MutatingGrid2DTraversal` non-Copyable would effectively close leaks #1, #2, and #3, b/c:

- I would explicitly have to write e.g. `leakedView = move(view)` (a *very* unlikely accident)
- I would also have to supply a "replacement value” for `view` by the end of the scope (impossible due to lack of public constructors)

…at least if I understand correctly. Is this accurate? If accurate, how likely would it be that “failed to provide replacement value for `view` after move” would get caught at compile time?

It would be guaranteed to get caught at compile time.

This leaking issue is something I didn't get into in the manifesto, but we've actually thought a fair amount about it. Generalized accessors come up a lot in the context of array slices, which share a lot of similar properties with your scenario. With array slices, we have some additional problems:
  - arrays are copy-on-write values, and the original array does need to keep its buffer alive while a slice is being accessed
  - slices need to be usable as independent (and copyable) value types; thus at least sometimes they need to have a strong reference to the buffer
  - forming a mutable slice really shouldn't form a second strong reference to the buffer because then mutations of the slice will trigger a buffer copy
The current line of thinking is that maybe we can have explicit copy and move hooks so that e.g. a projected slice could hold an unowned reference to the buffer which would be promoted to a strong reference on move/copy. But that's a lot of complexity, and I don't think it helps you that much.

Your analysis is correct: making the type move-only solves many of these problems, but not all of them because of the ability to move values aside. Rust has a concept of types that can't even be moved, I think; maybe we need to explore that.

John.

Thanks again for providing such detailed clarifications about this proposal.

The proposal suggests doing this instead with storage, so that the view is logically a (mutable) component of the grid. So on the use side:

  var grid = ...
  inout view = &grid[traversingFrom: p, following: m]
  view.mutate()

and on the declaration side:

  struct Grid2D<T> {
    subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {
      read {
        yield Grid2DTraversal(...)
      }
      modify {
        var traversal = Grid2DTraversal(...)
        yield &traversal
        // ensure changes were applied here
      }
    }
  }

If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.

John.

Anyways, it’s not clear to me, personally, whether or not the above is within the scope of any likely, concrete ownership system that’d follow from the manifesto or not…but if at all possible I’d prefer the eventual ownership system make it reasonable—and reasonably safe—to implement “small-c ‘collection’s that can safely-and-efficiently expose various *mutable* views as big-C `Collection`s”.

Apologies if all of the above considerations have answers that follow trivially from the manifesto; it’s just unclear personally whether the features described in the manifesto would work together to allow something like the above to be implemented more-reasonably than currently the case.

On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev@devandartist.com <mailto:adrian.zubarev@devandartist.com>> wrote:
Hi John, would you mind creating a markdown document for this manifesto in swift/docs at main · apple/swift · GitHub? :)

Yes, it should go in the repository. That commit is pending, but the in meantime, you can see the document properly rendered at:
  swift/OwnershipManifesto.md at 4c67c1d45b6f9649cc39bbb296d63663c1ef841f · rjmccall/swift · GitHub

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

What is the status of ownership in Swift?

A couple of days ago protocol “Sendable” in SE-302 was accepted, I got the impression that this might be a building stone in Ownership implementation? Or am I completely lost?

Is Ownership on any roadmap with a coarsed grained scheduled release?

10 Likes

ARC became quick enough to be bothered? Swift Performance - #105 by Joe_Groff
other optimizations are also either done or possible (e.g. immortal objects or thread bound objects).