[swift-evolution] [Manifesto] Ownership

Matthew Johnson matthew at anandabits.com
Mon Feb 20 15:54:35 CST 2017


> On Feb 20, 2017, at 3:38 PM, John McCall <rjmccall at apple.com> wrote:
> 
>> On Feb 20, 2017, at 4:26 PM, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
>>> On Feb 19, 2017, at 11:24 PM, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
>>> 
>>>> On Feb 18, 2017, at 11:08 AM, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
>>>> 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! :)

> 
> John.
> 
>> 
>>> 
>>> John.
>>> 
>>>> 
>>>>> On Feb 17, 2017, at 11:08 AM, John McCall via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>>> 
>>>>>> On Feb 17, 2017, at 4:50 AM, Adrian Zubarev <adrian.zubarev at devandartist.com <mailto:adrian.zubarev at devandartist.com>> wrote:
>>>>>> Hi John, would you mind creating a markdown document for this manifesto in https://github.com/apple/swift/tree/master/docs <https://github.com/apple/swift/tree/master/docs>? :)
>>>>>> 
>>>>>> 
>>>>> Yes, it should go in the repository.  That commit is pending, but the in meantime, you can see the document properly rendered at:
>>>>>   https://github.com/rjmccall/swift/blob/4c67c1d45b6f9649cc39bbb296d63663c1ef841f/docs/OwnershipManifesto.md <https://github.com/rjmccall/swift/blob/4c67c1d45b6f9649cc39bbb296d63663c1ef841f/docs/OwnershipManifesto.md>
>>>>> 
>>>>> John.
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170220/6538dff6/attachment.html>


More information about the swift-evolution mailing list