RFC: Preventing Retain Cycles (Memory Ownership Model)

ownership

(Andrew Bennett) #1

I'd like an *opt-in* way to verify and prevent *unintentional strong
references* in Swift.

This can be used to verify ownership structures, and ultimately avoid
retain cycles.

Read a draft proposal here:

TL;DR:

If you have any questions please read the proposal before asking here.

It's an opt-in attribute that defines a whitelist of types something can
own. For example:

@owns(TypeA, TypeB) struct TypeC { ... }

I wrote this a few months ago, but we weren't accepting additive proposals.
Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory

···

ownership model to Swift is highly desired by systems programmers and folks
who want predictable and deterministic performance (for example, in real
time audio processing code). More pertinent to the goals of Swift 4, this
feature is important because it fundamentally shapes the ABI. It informs
code generation for “inout", how low-level “addressors” work in the ABI,
impacts the Swift runtime, and will have a significant impact on the type
system and name mangling.

- Chris
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html>

----

Here's a link to the version of the proposal
<https://github.com/therealbnut/swift-evolution/commit/6ab167825d802c7826804e1957eb515d3009743a>
when
I sent this email.


(Félix Cloutier) #2

Seems to me that we can find similar information just from walking over a class's fields to build an ownership graph, and cause warnings/errors when you find a strong cycle.

How do you deal with type erasure?

protocol Foo {}
class A {
  var foo: Foo
}
class B: Foo {
  var a: A
}
// A and B can have a cycle through the Foo protocol

Also, how do you encode that your example's "addCallback" closure parameter can't have a strong reference to `self`?

Félix

···

Le 29 juil. 2016 à 18:42:11, Andrew Bennett via swift-evolution <swift-evolution@swift.org> a écrit :

I'd like an opt-in way to verify and prevent unintentional strong references in Swift.

This can be used to verify ownership structures, and ultimately avoid retain cycles.

Read a draft proposal here:
https://github.com/therealbnut/swift-evolution/blob/therealbnut-explicit-ownership/proposals/NNNN-explicit-ownership-type-attribute.md

TL;DR:

If you have any questions please read the proposal before asking here.

It's an opt-in attribute that defines a whitelist of types something can own. For example:

@owns(TypeA, TypeB) struct TypeC { ... }

I wrote this a few months ago, but we weren't accepting additive proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory ownership model to Swift is highly desired by systems programmers and folks who want predictable and deterministic performance (for example, in real time audio processing code). More pertinent to the goals of Swift 4, this feature is important because it fundamentally shapes the ABI. It informs code generation for “inout", how low-level “addressors” work in the ABI, impacts the Swift runtime, and will have a significant impact on the type system and name mangling.

- Chris <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html>

----

Here's a link to the version of the proposal <https://github.com/therealbnut/swift-evolution/commit/6ab167825d802c7826804e1957eb515d3009743a> when I sent this email.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #3

Memory ownership is about something slightly different than this. In the context of Swift, the model we’re looking for is:

- You can completely ignore memory ownership features of the language, and get very far into development with Swift. This is in stark contrast with Rust and Cyclone, which require you to grapple with it up front. This means that in the Swift context, this will be more of a “power user” feature, instead of essential part of the model.

- You can choose to use the memory ownership features by adding extra annotations, giving better performance and control over ARC. Right now we have very limited options for avoiding ARC overhead in critical loops, largely forcing you to drop down to unsafe constructs. We’d prefer the model to be “you can add more annotations to your code to get better performance, allowing the compiler statically verify correctness instead of dynamically”.

- Memory ownership control is an extremely non-trivial feature, which will probably drive us to add first class move semantics and region types to the language. This will also call for significant standard library extensions. It will pay for this complexity by making it easy to ignore the complexity if you don’t want it, and by the fact that the standard library and other stuff can go much faster.

- As a Stage 2 feature, I can imagine an opt-in mode that “forces” the use of these features, for code that wants to guarantee deterministic performance. This is what enables the use of swift in realtime audio applications, for example.

While some initial brainstorming and scoping has been done in this area, we’re far from having a concrete design. We have a few folks who are experts at Rust that are helping contribute ideas and experience to this though.

If you have more specific questions, feel free to ask about it.

-Chris

···

On Jul 29, 2016, at 6:42 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

I wrote this a few months ago, but we weren't accepting additive proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory ownership model to Swift is highly desired by systems programmers and folks who want predictable and deterministic performance (for example, in real time audio processing code). More pertinent to the goals of Swift 4, this feature is important because it fundamentally shapes the ABI. It informs code generation for “inout", how low-level “addressors” work in the ABI, impacts the Swift runtime, and will have a significant impact on the type system and name mangling.


(Haravikk) #4

This is very interesting, but it'll probably be a little while before I can fully get my head around it.

One query though; an example mentioned is adding @owns(Element) to the Generator protocol, but associated types feel a little different to me; you mention using the strong keyword as an alternative, but I wonder if that might actually be a better fit for the associated type case, while @owns works elsewhere, or perhaps strong could even be made a shorthand for simpler cases? Just thinking out loud I guess, it would be nice to hear the thought process around associated types; most (possibly all I don't remember) cases in which I've used associated types it has been for strong references, so it seems like that should be as easy as possible to do under the new opt-in approach.

But yeah, I generally agree that this ought to be opt-in, as it's an area I do stumble upon quite a bit myself (in many languages).

···

On 30 Jul 2016, at 02:42, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

I'd like an opt-in way to verify and prevent unintentional strong references in Swift.

This can be used to verify ownership structures, and ultimately avoid retain cycles.

Read a draft proposal here:
https://github.com/therealbnut/swift-evolution/blob/therealbnut-explicit-ownership/proposals/NNNN-explicit-ownership-type-attribute.md

TL;DR:

If you have any questions please read the proposal before asking here.

It's an opt-in attribute that defines a whitelist of types something can own. For example:

@owns(TypeA, TypeB) struct TypeC { ... }

I wrote this a few months ago, but we weren't accepting additive proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory ownership model to Swift is highly desired by systems programmers and folks who want predictable and deterministic performance (for example, in real time audio processing code). More pertinent to the goals of Swift 4, this feature is important because it fundamentally shapes the ABI. It informs code generation for “inout", how low-level “addressors” work in the ABI, impacts the Swift runtime, and will have a significant impact on the type system and name mangling.

- Chris <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html>

----

Here's a link to the version of the proposal <https://github.com/therealbnut/swift-evolution/commit/6ab167825d802c7826804e1957eb515d3009743a> when I sent this email.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Andrew Bennett) #5

Answers inline:

Seems to me that we can find similar information just from walking over a
class's fields to build an ownership graph, and cause warnings/errors when
you find a strong cycle.

This is true, but the intent is a whitelist, which is explicit and cannot
be automated. The intent is to catch as many unintentional strong
references as possible. If you walked the fields, methods, and all uses you
could get the same information, but you wouldn't know if they're
intentional.

It may be possible to imply that something owns fields, but the annotation
may need to be more specific than what that produces. For example:
closures, or collections.

How do you deal with type erasure?

That's an interesting point. Currently it will behave much the same as
other collection types. The collection must designate ownership of its
associatedtypes. If that's a protocol then the ownership should be
inherited from the protocol.

protocol Foo {}
class A {
var foo: Foo
}
class B: Foo {
var a: A
}

// A and B can have a cycle through the Foo protocol

Also, how do you encode that your example's "addCallback" closure
parameter can't have a strong reference to `self`?

You encode it by not including it in the list of owned types. If you want
to be able to have a strong reference to self you'd need `@owns(self)`.

···

On Sat, Jul 30, 2016 at 2:17 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

Félix

Le 29 juil. 2016 à 18:42:11, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> a écrit :

I'd like an *opt-in* way to verify and prevent *unintentional strong
references* in Swift.

This can be used to verify ownership structures, and ultimately avoid
retain cycles.

Read a draft proposal here:

https://github.com/therealbnut/swift-evolution/blob/therealbnut-explicit-ownership/proposals/NNNN-explicit-ownership-type-attribute.md

TL;DR:

If you have any questions please read the proposal before asking here.

It's an opt-in attribute that defines a whitelist of types something can
own. For example:

@owns(TypeA, TypeB) struct TypeC { ... }

I wrote this a few months ago, but we weren't accepting additive
proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory

ownership model to Swift is highly desired by systems programmers and folks
who want predictable and deterministic performance (for example, in real
time audio processing code). More pertinent to the goals of Swift 4, this
feature is important because it fundamentally shapes the ABI. It informs
code generation for “inout", how low-level “addressors” work in the ABI,
impacts the Swift runtime, and will have a significant impact on the type
system and name mangling.

- Chris
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html>

----

Here's a link to the version of the proposal
<https://github.com/therealbnut/swift-evolution/commit/6ab167825d802c7826804e1957eb515d3009743a> when
I sent this email.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Andrew Bennett) #6

Thanks for the detailed response :slight_smile:

My mistake, I was thinking more in terms of managing a user's expectations
regarding ownership and avoiding retain cycles.

What you've described sounds great. I imagine it should only affect this
proposal if the solution it provides adds additional checks for users
accidentally taking strong references.

···

On Sat, Jul 30, 2016 at 2:21 PM, Chris Lattner <clattner@apple.com> wrote:

On Jul 29, 2016, at 6:42 PM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:

I wrote this a few months ago, but we weren't accepting additive
proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory

ownership model to Swift is highly desired by systems programmers and folks
who want predictable and deterministic performance (for example, in real
time audio processing code). More pertinent to the goals of Swift 4, this
feature is important because it fundamentally shapes the ABI. It informs
code generation for “inout", how low-level “addressors” work in the ABI,
impacts the Swift runtime, and will have a significant impact on the type
system and name mangling.

Memory ownership is about something slightly different than this. In the
context of Swift, the model we’re looking for is:

- You can completely ignore memory ownership features of the language, and
get very far into development with Swift. This is in stark contrast with
Rust and Cyclone, which require you to grapple with it up front. This
means that in the Swift context, this will be more of a “power user”
feature, instead of essential part of the model.

- You can choose to use the memory ownership features by adding extra
annotations, giving better performance and control over ARC. Right now we
have very limited options for avoiding ARC overhead in critical loops,
largely forcing you to drop down to unsafe constructs. We’d prefer the
model to be “you can add more annotations to your code to get better
performance, allowing the compiler statically verify correctness instead of
dynamically”.

- Memory ownership control is an extremely non-trivial feature, which will
probably drive us to add first class move semantics and region types to the
language. This will also call for significant standard library
extensions. It will pay for this complexity by making it easy to ignore
the complexity if you don’t want it, and by the fact that the standard
library and other stuff can go much faster.

- As a Stage 2 feature, I can imagine an opt-in mode that “forces” the use
of these features, for code that wants to guarantee deterministic
performance. This is what enables the use of swift in realtime audio
applications, for example.

While some initial brainstorming and scoping has been done in this area,
we’re far from having a concrete design. We have a few folks who are
experts at Rust that are helping contribute ideas and experience to this
though.

If you have more specific questions, feel free to ask about it.

-Chris


(Colin Barrett) #7

I wrote this a few months ago, but we weren't accepting additive proposals. Now we're explicitly looking for something like this:

Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory ownership model to Swift is highly desired by systems programmers and folks who want predictable and deterministic performance (for example, in real time audio processing code). More pertinent to the goals of Swift 4, this feature is important because it fundamentally shapes the ABI. It informs code generation for “inout", how low-level “addressors” work in the ABI, impacts the Swift runtime, and will have a significant impact on the type system and name mangling.

Memory ownership is about something slightly different than this. In the context of Swift, the model we’re looking for is:

- You can completely ignore memory ownership features of the language, and get very far into development with Swift. This is in stark contrast with Rust and Cyclone, which require you to grapple with it up front. This means that in the Swift context, this will be more of a “power user” feature, instead of essential part of the model.

- You can choose to use the memory ownership features by adding extra annotations, giving better performance and control over ARC. Right now we have very limited options for avoiding ARC overhead in critical loops, largely forcing you to drop down to unsafe constructs. We’d prefer the model to be “you can add more annotations to your code to get better performance, allowing the compiler statically verify correctness instead of dynamically”.

Has any thought been giving to opting in something analogous in the other direction—i.e. less performant, but less work for the programer? Specifically, I’ve long thought that an annotation opting into a runtime cycle collector (a la http://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf) would be very helpful for situations where, as you mention, performance is not (currently) critical.

-Colin

···

On Jul 30, 2016, at 12:21 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
On Jul 29, 2016, at 6:42 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

- Memory ownership control is an extremely non-trivial feature, which will probably drive us to add first class move semantics and region types to the language. This will also call for significant standard library extensions. It will pay for this complexity by making it easy to ignore the complexity if you don’t want it, and by the fact that the standard library and other stuff can go much faster.

- As a Stage 2 feature, I can imagine an opt-in mode that “forces” the use of these features, for code that wants to guarantee deterministic performance. This is what enables the use of swift in realtime audio applications, for example.

While some initial brainstorming and scoping has been done in this area, we’re far from having a concrete design. We have a few folks who are experts at Rust that are helping contribute ideas and experience to this though.

If you have more specific questions, feel free to ask about it.

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


(Chris Lattner) #8

We have certainly discussed cycle collectors in the past, even in the context of Objective-C, and have concluded that it would be a bad idea for several reasons. If you’d like to discuss that, please start a new thread, thanks!

-Chris

···

On Jul 30, 2016, at 3:21 PM, Colin Barrett <colin@springsandstruts.com> wrote:

- You can choose to use the memory ownership features by adding extra annotations, giving better performance and control over ARC. Right now we have very limited options for avoiding ARC overhead in critical loops, largely forcing you to drop down to unsafe constructs. We’d prefer the model to be “you can add more annotations to your code to get better performance, allowing the compiler statically verify correctness instead of dynamically”.

Has any thought been giving to opting in something analogous in the other direction—i.e. less performant, but less work for the programer? Specifically, I’ve long thought that an annotation opting into a runtime cycle collector (a la http://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf) would be very helpful for situations where, as you mention, performance is not (currently) critical.