[swift-evolution] [Manifesto] Ownership

John McCall rjmccall at apple.com
Mon Feb 27 11:08:38 CST 2017


> On Feb 25, 2017, at 11:41 AM, plx via swift-evolution <swift-evolution at swift.org> wrote:
> 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.

> Point fixes like the custom `.values` collection on `Dictionary` that just got approved are useful, but hopefully ownership can provide a general solution.
> 
> 2: Mutating Iteration & Granularity
> 
> If I understood the mutating-iteration section right it reads as if `for inout` would only be available on `MutableCollection`. Is that correct?
> 
> If so that does seem limiting, as e.g. for a `Dictionary` it’d be nice if something like this were expressible:
> 
>   for (key, inout value) in someDictionary {
>   }
> 
> …assuming there’s not some insurmountable technical obstacle.

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.

> 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.

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 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>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170227/bda62662/attachment-0001.html>


More information about the swift-evolution mailing list