<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I ran into this exact issue today. Would something like inout returns help to fix it?<div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>styled.paragraph(2).words(3…7).bold = true</div><div class=""><br class=""></div><div class="">and then at the end, you ask for an attributed string:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>myLabel.attributedText = styled.attributedString</div><div class=""><br class=""></div><div class="">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. </div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Jon</div><div class=""><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Feb 27, 2017, at 9:08 AM, John McCall via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">3: Mutable Views</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""> /// Implements a 2D grid (of size fixed upon initialization).</div><div class=""> /// **Not** a `Collection` itself but has many *views* into it that *are* `Collection`s.</div><div class=""> ///</div><div class=""><div class=""> struct Grid2D<T> {</div><div class=""> // typical CoW backing storage</div><div class=""> fileprivate var storage: Grid2DStorage<T></div><div class=""> </div><div class=""> /// Obtain a linear traversal of our grid:</div><div class=""> /// - parameter corner: The corner at which we start (e.g. `northWest`)</div><div class=""> /// - parameter motion: The order in which we travel (`latitudeThenLongitude` or `longitudeThanLatitude`)</div><div class=""> ///</div><div class=""> /// - returns: A read-only `Collection` that visits each grid location in `self`, following the requested traversal</div><div class=""> func traversal(from corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T></div><div class=""> }</div></div><div class=""><br class=""></div><div class="">…wherein `Grid2DTraversal<T>` is, as noted, a "read-only view” into its parent that also adopts `Collection`.</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""> extension Grid2D {</div><div class=""> </div><div class=""> mutating func mutatingTraversal<T>(from corner: Grid2DCorner, following motion: Grid2DMotion, _ mutator: (inout Grid2DTraversal<T>) -> R) -> R {</div><div class=""> var t = self.traversal(from: corner, following: motion)</div><div class=""> return mutator(&t)</div><div class=""> }</div><div class=""><br class=""></div><div class=""> }</div><div class=""><br class=""></div><div class="">…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.</div><div class=""><br class=""></div><div class="">As it is the “best” way to squeeze this into the type system at this time is arguably:</div><div class=""><br class=""></div><div class="">- define Grid2DTraversal:</div><div class=""> - to have as a strong reference to the backing storage</div><div class=""> - as only having the read-only methods</div><div class="">- *also* define MutableGrid2DTraversal:</div><div class=""> - to have an unowned reference to the backing storage</div><div class=""> - also include the mutating methods</div><div class=""><br class=""></div><div class="">…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.</div><div class=""><br class=""></div><div class="">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`:</div><div class=""><br class=""></div><div class="">- to adopt `Collection` without restriction</div><div class="">- to adopt `MutableCollection` only in certain ownership contexts</div><div class="">- to have reasonable control over where those contexts apply </div></div></div></blockquote><div class=""><br class=""></div>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:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> var grid = ... // note that this is mutable</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> var view = grid.traversal(from: p, following: m) // should return a mutable view by design, right?</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> view.mutate() // reflected in grid, right?</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">then it completely destroys the value-type properties of 'grid', because 'view' should really be an independent value.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">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:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> var grid = ...</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> inout view = &grid[traversingFrom: p, following: m]</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> view.mutate()</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">and on the declaration side:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> struct Grid2D<T> {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> subscript(traversingFrom corner: Grid2DCorner, following motion: Grid2DMotion) -> Grid2DTraversal<T> {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> read {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> yield Grid2DTraversal(...)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> modify {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> var traversal = Grid2DTraversal(...)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> yield &traversal</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> // ensure changes were applied here</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">If you feel that the aesthetics of this leave something to be desired, that's a totally reasonable thing to discuss.</div></div></blockquote></div><br class=""></div></div></body></html>