[swift-evolution] [Proposal] Scoped resources (like C# using statement)

Joe Groff jgroff at apple.com
Wed Dec 30 15:33:49 CST 2015

> On Dec 30, 2015, at 1:27 PM, Kevin Ballard <kevin at sb.org> wrote:
> On Wed, Dec 30, 2015, at 09:53 AM, Joe Groff wrote:
>>> On Dec 29, 2015, at 8:55 PM, Kevin Ballard via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 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).
>> deinit doesn't make sense for value types. Classes already support deinit, and you can use withExtendedLifetime to bound the lifetime of a resource-holding class. It would be reasonable to have a scoped lifetime marker similar to ObjC ARC too.
> If you run with the idea that any resource-holding class should also be the mechanism by which you access the resource (e.g. a LockGuard that represents holding the lock and also provides access to the guarded value) then there's no need for extended lifetimes, because as long as you're accessing the resource, you're keeping the resource-holding class alive. I suppose there might be rare cases where you need to extend the lifetime of a resource-holding class even when you're not accessing the resource, just to guarantee e.g. order of resource releasing, but you can always just say something like `withExtendedLifeetime(&val) {}` at the end of the scope to ensure the value is still alive at that point. Although I'd really like to define `_ = val` as guaranteeing that the value is alive at that point (the expression doesn't actually do anything, but because it references `val` it expresses the programmer's intent that `val` should still be alive at that point in time). Alternatively, if we end up with move-only structs (or uniquely-owned classes), we could even define the expression `_ = val` as "dropping" the value , i.e. forcing it to deinit at that spot (because it's moving the value out of the `val` variable). This would be analogous to Rust's `std::mem::drop()` function (which is literally defined as `pub fn drop<T>(_x: T) { }` because all it does is move the value into the function and then forget about it).

Another possibility I've thought of is defining `defer { val }` to guarantee that val remains alive until the defer fires on scope exit. That might let us leave `defer` as the one "guarantee something happens exactly at scope exit" language construct.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151230/585e7a5a/attachment.html>

More information about the swift-evolution mailing list