<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body><div>There's no rule-of-five if you explicitly define (as Rust does) that you cannot override assign/copy/move. In Rust, a copyable struct is always memcpy()'d. Anything that's not memcpy'd but still wants to support explicit copying conforms to the Clone trait, and the compiler lets such structs automatically derive Clone (the Clone trait provides a single method .clone() that returns a copy of the struct). So it's basically just init, which we already require (though we infer an init if you don't otherwise define one), deinit which is totally optional, and then just one line to derive a Clone implementation if appropriate (and of course you can always manually implement Clone if you need special logic to do so, e.g. the Arc type (Atomic Reference Counted) manually implements Clone in order to bump the retain count, but that's actually pretty rare, usually structs that need to actually do things (like bump retain counts) on clone are composed of smaller pieces (like Arc) that do that automatically).<br></div>
<div>&nbsp;</div>
<div>Overall this system works pretty well. Because you can't override assign/copy/move, you can move and copy structs around without worry (just as we do in Swift). And if a struct is not copyable, you can invoke .clone() and it's obvious from the code that you're doing something  more expensive than just a memcpy(). This system also encourages the use of references when possible because it lets you avoid the potentially-expensive clones (versus overriding copy, where you end up invoking potentially-expensive copies without even realizing it). Of course, this does require actually having references in the language to begin with.<br></div>
<div>&nbsp;</div>
<div>Ultimately, given Swift's current direction, I'm leaning right now towards the idea of having uniquely-owned stack-allocated classes, and that's basically just because classes are already a reference type, which makes it a bit easier to explain adding magic that lets you say things like non-mutating methods are acting on a reference (even though it's stack-allocated) and provides an avenue for doing things like saying things like `func foo(x: ref LockGuard&lt;Bar&gt;)` to represent the idea of a pass-by-reference that's treated as @noescape (or the alternative, `func foo(x: move LockGuard&lt;Bar&gt;)` that explicitly moves the value, except we do need the @noescape part of passing a reference to a uniquely-owned value so I think annotating the parameter with `ref` or `in` makes more sense).<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard</div>
<div>&nbsp;</div>
<div>On Wed, Dec 30, 2015, at 01:40 PM, Dave Abrahams wrote:<br></div>
<blockquote type="cite"><div>&nbsp;</div>
<div>IMO the biggest problem with this approach is that it leads to a much more complicated programming model. &nbsp;The vast majority of structs&nbsp;<i>should</i>&nbsp;be copiable, which gets you into rule-of-five programming (where nearly every nontrivial struct needs to implement init, deinit, copy, assign, move) pretty quickly. &nbsp;I don’t think Swift should go down this road. &nbsp;<br></div>
<div>&nbsp;</div>
<div>We do need a way to handle atomics, but I think there are other ways to address some of these concerns, including optimizing away class heap allocations and refcounting in special cases.&nbsp;<br></div>
<div>&nbsp;</div>
<div><div>-Dave<br></div>
</div>
<div>&nbsp;</div>
<div><blockquote type="cite"><div>On Dec 29, 2015, at 8:55 PM, Kevin Ballard via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div>
<div>&nbsp;</div>
<div><div><div>An alternative solution is to do what Rust and C++ do, which is to use RAII. Which is to say, instead of introducing a new language construct that's explicitly tied to a scope, you just use a struct to represent the resource that you hold (e.g. a File that represents an open file). Of course, this does require some changes to structs, notably the addition of a deinit. And if structs have a deinit, then they also need to have a way to restrict copies. This is precisely what Rust does; any struct in Rust that implements Drop (the equivalent to deinit) loses the ability to be implicitly copied (a second trait called Clone provides a .clone() method that is the normal way to copy such non-implicitly-copyable structs).<br></div>
<div>&nbsp;</div>
<div>This solution is elegant for a few reasons:<br></div>
<div>&nbsp;</div>
<div>1. Once you allow deinit on structs (which is useful) and deal with the fact that structs are no longer implicitly copyable (because almost all deinit functions on structs won't work right if they're called twice, such as on two copies), then RAII just sort of falls out of all of this and doesn't require any specific language features.<br></div>
<div>2. It's more flexible, because you can actually return the RAII value from a scope in order to extend its lifetime.<br></div>
<div>3. The RAII value itself provides the means to access the resource it's protecting; e.g. a Lock might return a LockGuard RAII value from the .lock() method, and LockGuard provides the means to access the protected value (as opposed to just having the lock sitting next to the value, which makes it trivially easy to accidentally access the value without holding the lock).<br></div>
<div>4. In Rust, this pattern also integrates extremely well with Rust's lifetime system (the system that prevents data races / memory corruption at compile time), because e.g. a LockGuard contains the lifetime of the Lock, which prevents you at compile-time from attempting to lock the Lock while you already have it locked (though it doesn't prevent deadlocks where you and another thread try and lock two locks in opposite orders, but there is plenty of stuff it does catch).<br></div>
<div>&nbsp;</div>
<div>The biggest problem with adding deinit to structs in Swift right now is the fact that we don't have references, which means you can't take a RAII struct and pass it to another function without losing it. Heck, you can't even call a method on it, because `self` on non-mutating methods in Swift is a value and not a reference (although we could hand-wave that away and make `self` in non-mutating RAII methods actually be an "in" reference internally, but this kind of hand-waving doesn't work when passing the struct as an argument to another function). So we'd actually have to introduce a special "in" reference, which would be like "inout" except it doesn't actually copy it out (and is guaranteed to actually pass a pointer, although this pointer may be a pointer to a temporary). Except even that fails if you want to have a computed property that returns an existing RAII value (for example, having an Array of these things; barring optimizations, the subscript getter returns a computed value). And you can't generalize such "in" references beyond function arguments without basically providing raw C pointers. Rust's lifetime system lets them do it safely, but barring such a system, Swift can't really do this (I assume it's obvious why we don't want to start using raw C pointers everywhere).<br></div>
<div>&nbsp;</div>
<div>All that said, I think this is a problem Swift needs to solve, because having non-copyable structs would be very useful. In particular, I _really_ want some way to do atomics in Swift, but the only safe way I can think of to do it requires non-copyable structs (because it's not correct to do a nonatomic read (such as a memcpy) of an atomic that's visible to other threads). I suppose you could provide a way to override how struct copies work (e.g. so you could do an atomic read of the old value), but it's rather problematic to break the assumption that struct copies are cheap.<br></div>
<div>&nbsp;</div>
<div>Of course, you could model RAII with classes instead of structs, that just has the overhead of heap allocation (+ atomic reference counting) for every RAII value.<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard<br></div>
<div>&nbsp;</div>
<div>On Tue, Dec 29, 2015, at 08:02 PM, Trent Nadeau via swift-evolution wrote:<br></div>
<blockquote type="cite"><div dir="ltr"><div># Introduction<br></div>
<div>&nbsp;</div>
<div><div>Add a new `Scoped` protocol and enhance the do statement to automatically call enter/exit actions on resources.<br></div>
<div>&nbsp;</div>
<div># Motivation<br></div>
<div>&nbsp;</div>
<div>Resources (e.g., locks, files, sockets, etc.) often need to be scoped to a block, where some action is taken at the start of the block and another is required at the end. Examples include locking and unlocking a lock in a critical section or closing a file at the end of a block.<br></div>
<div>&nbsp;</div>
<div>Doing this manually is possible using `defer` statements among other options, but this is error prone as a `defer` can be forgotten, `lock`/`unlock` calls for two locks can be switched due to a typo, etc. Having a dedicated language construct for this common case makes it easier to read and write while making code shorter and clearer.<br></div>
<div>&nbsp;</div>
<div># Language Survey<br></div>
<div>&nbsp;</div>
<div>At least three major languages have widely used statements for this use case.<br></div>
<div>&nbsp;</div>
<div>## C#<br></div>
<div>&nbsp;</div>
<div>C# has the `using` statement and the associated `IDisposable` interface.<br></div>
<div>&nbsp;</div>
<div>```csharp<br></div>
<div><div>using (StreamReader sr = new StreamReader(filename)) {<br></div>
<div>&nbsp; &nbsp; txt = sr.ReadToEnd();<br></div>
<div>}<br></div>
</div>
<div>```<br></div>
<div>&nbsp;</div>
<div>C#'s solution only handles close/exit actions via the `IDisposable.Dispose()` method and so cannot easily be used with items such as locks; however, C# has the additional `lock` statement for that use case.<br></div>
<div>&nbsp;</div>
<div>## Java<br></div>
<div>&nbsp;</div>
<div>Java has try-with-resources and the associated `AutoCloseable` interface.<br></div>
<div>&nbsp;</div>
<div>```java<br></div>
<div><div>try (BufferedReader br = new BufferedReader(new FileReader(path))) {<br></div>
<div>&nbsp; &nbsp; return br.readLine();<br></div>
<div>}<br></div>
</div>
<div>```<br></div>
<div>&nbsp;</div>
<div>Java's solution only handles close/exit actions via the `AutoCloseable.close()` method and so cannot easily be used with items such as locks; however, Java has the additional `synchronized` statement for that use case.<br></div>
<div>&nbsp;</div>
<div>## Python<br></div>
<div>&nbsp;</div>
<div>Python has with `with` statement and the associated `__enter__` and `__exit__` special methods that classes may implement to become a "context manager".<br></div>
<div>&nbsp;</div>
<div>```python<br></div>
<div>with lock, open(path) as my_file:<br></div>
<div>&nbsp; &nbsp; contents = my_file.read()<br></div>
<div>&nbsp; &nbsp; # use contents<br></div>
<div>```<br></div>
<div>&nbsp;</div>
<div>Python's solution handles both enter and exit actions and so this one construct is usable for locks as well as resources like sockets and files.<br></div>
<div>&nbsp;</div>
<div># Proposed Solution<br></div>
<div>&nbsp;</div>
<div>We add a new protocol called `Scoped` to the standard library. Types for resources that have enter/exit actions will be extended to add conformance to this protocol.<br></div>
<div>&nbsp;</div>
<div>The `do` statement will be extended to allow a new `using &lt;resources&gt;` "suffix".<br></div>
<div>&nbsp;</div>
<div># Detailed Design<br></div>
<div>&nbsp;</div>
<div>The `Scoped` protocol shall be as follows:<br></div>
<div>&nbsp;</div>
<div>```swift<br></div>
<div><div>public protocol Scoped {<br></div>
<div>&nbsp; &nbsp; func enterScope()<br></div>
<div>&nbsp; &nbsp; func exitScope()<br></div>
<div>}<br></div>
</div>
<div>```<br></div>
<div>&nbsp;</div>
<div>The compiler statement will accept a new form for resources. For example,<br></div>
<div>&nbsp;</div>
<div>```swift<br></div>
<div>do using lock, let file = try getFileHandle() {<br></div>
<div>&nbsp; &nbsp; // statements<br></div>
<div>}<br></div>
<div>```<br></div>
<div>&nbsp;</div>
<div>As can be seen in the example above, the resources can be bindings that already exist (like `lock`) or can be new bindings. Bindings created with `do using` are not available outside of the scope of the `do using`. Only types conforming to `Scoped` may be using with `do using`. Use of non-conforming types will result in a compiler error.<br></div>
<div>&nbsp;</div>
<div>The above example would be syntactic sugar for the following:<br></div>
<div>&nbsp;</div>
<div>```swift<br></div>
<div><div>do {<br></div>
<div>&nbsp; &nbsp; lock.enterScope()<br></div>
<div>&nbsp; &nbsp; defer { lock.exitScope() }<br></div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; let file = try getFileHandle()<br></div>
<div>&nbsp; &nbsp; file.enterScope()<br></div>
<div>&nbsp; &nbsp; defer { file.exitScope() }<br></div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; // statements<br></div>
<div>}<br></div>
</div>
<div>```<br></div>
<div>&nbsp;</div>
<div># Framework Changes / Examples<br></div>
<div>&nbsp;</div>
<div><div>As an example of some real-world classes that would be useful with `Scoped`, from Foundation:<br></div>
<div>&nbsp;</div>
<div>```swift<br></div>
<div>// Would be nice to extend the NSLocking protocol instead, but that's not supported yet.<br></div>
<div>extension NSLock: Scoped {<br></div>
<div>&nbsp; &nbsp; func enterScope() {<br></div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; self.lock()<br></div>
<div>&nbsp; &nbsp; }<br></div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; func exitScope() {<br></div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; self.unlock()<br></div>
<div>&nbsp; &nbsp; }<br></div>
<div>}<br></div>
<div>&nbsp;</div>
<div>extension NSFileHandle: Scoped {<br></div>
<div>&nbsp; &nbsp; func enterScope() {}<br></div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; func exitScope() {<br></div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; self.closeFile()<br></div>
<div>&nbsp; &nbsp; }<br></div>
<div>}<br></div>
</div>
<div>```<br></div>
<div>&nbsp;</div>
<div># Questions and Concerns<br></div>
<div>&nbsp;* Bikeshedding protocol naming and scoping syntax<br></div>
<div>&nbsp;* Should the enter and exit actions be allowed to throw errors?<br></div>
<div><div>&nbsp;</div>
<div>-- <br></div>
<div>Trent Nadeau<br></div>
</div>
</div>
</div>
<div><img src="https://www.fastmailusercontent.com/proxy/49ec52f263997d0135ceb5018b2d5341293d4d97e48c2718e723fd171c3cb8b2/8647470737a3f2f2777777e266163747d61696c65737562736f6e64756e647e236f6d6f20727f68797f293130316132633835663465673133356164636736366467333531303469323164683536363365636134616662336663346468373234393561353336663831626f2836343734373037333731633662366235373233303330333233343331333033356233363437356233373536356634363736323739363436356235663536343736623737363636623666303735363566366335373037356634633134383736353137363738363366373331373136313431673462323336343534323330333435323732373736356434363735313433333533393431353264343736333666343334663836336434343535363631333537383439373165316631373035333736363037333730353336363335363833363436333137303539343136346232333634363535363037303531673536313437363133346439373336383335363237373430333536353633353462323336343634313430373167353436373566383731653734333332363937336437363836323635643735393536663633333633363633353634643837353337353035363636373836346232333634356632643164373434643664316430353433316735643566343432363234313735363335383735663534393635333534313636363137333431653834353639333637373434333134323537343936353337353636383639343436383433333337373332333634333734333534356438333635373636333335383738353934326439373435313437343035383531673636336439353935316431673037373436643337343335663464383331363833323435333437366439333164353437373462333334343462333334343f2f60756e6/open" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-top-width:0px !important;border-right-width:0px !important;border-bottom-width:0px !important;border-left-width:0px !important;margin-top:0px !important;margin-bottom:0px !important;margin-right:0px !important;margin-left:0px !important;padding-top:0px !important;padding-bottom:0px !important;padding-right:0px !important;padding-left:0px !important;"><br></div>
<div><u>_______________________________________________</u><br></div>
<div>swift-evolution mailing list<br></div>
<div><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br></div>
<div><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div>
</blockquote><div>&nbsp;</div>
<div><img style="height:1px !important;width:1px !important;border-top-width:0px !important;border-right-width:0px !important;border-bottom-width:0px !important;border-left-width:0px !important;margin-top:0px !important;margin-bottom:0px !important;margin-right:0px !important;margin-left:0px !important;padding-top:0px !important;padding-bottom:0px !important;padding-right:0px !important;padding-left:0px !important;" border="0" height="1" width="1" alt="" src="https://www.fastmailusercontent.com/proxy/a2573bc682894fe49415f99f0784be6e5464b35d815ab2bfe07a286c60c0b12c/8647470737a3f2f25723030323431303e23647e23756e64676279646e2e65647f27766f2f60756e6f35707e6d3a466d40516d22364737777a505a737a53315b41483e4a647f4e49495854335a626755755874707663745952386f6e4f6a6b454946566345463a74583f48624564765a533148364932383e4546744247615850583172384f4c4a7638734472703c4841316a754959744749673a737d22324273415756693279457f4a4432567b454b6f64386075717a79705055445077314531363e4d42796076774a65747c637f4f407b645776403c617635725c4d223240565459377446596a535840376534396b603478766736556a564873547551747052495f4d4e6f447f69395056357562467458585f694f6e46703656375a74303d23344/open"><br></div>
</div>
<div>_______________________________________________<br></div>
<div>swift-evolution mailing list<br></div>
<div><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br></div>
<div>https://lists.swift.org/mailman/listinfo/swift-evolution<br></div>
</div>
</blockquote></div>
</blockquote><div>&nbsp;</div>
</body>
</html>