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

Trent Nadeau tanadeau at gmail.com
Wed Dec 30 00:45:31 CST 2015


I disagree that `do using` would be useless for resources. Essentially no
Cocoa resource classes have a `deinit`. NSFileHandle, NSStream, etc.
require a close-like call to free the underlying resource. Also, per the
Swift documentation about deinitialization:

    "Typically you don’t need to perform manual clean-up when your
instances are deallocated. However, when you are working with your own
resources, you might need to perform some additional clean-up yourself. For
example, if you create a custom class to open a file and write some data to
it, you might need to close the file before the class instance is
deallocated."

On Wed, Dec 30, 2015 at 1:19 AM, Félix Cloutier <felixcca at yahoo.ca> wrote:

> My understanding is that you suggest using the "do using" statement for
> two purposes:
>
>
>    1. to deterministically free resources (files, sockets);
>    2. to create a scope with a guarantee about something (locks).
>
>
> The first purpose is very relevant for garbage-collected languages because
> the GC generally only monitors memory pressure to decide when to run, and
> so the GC won't budge if you're running out of file descriptors even if
> some could be reclaimed. However, Swift is not garbage-collected and
> resources are already reclaimed deterministically. If you create a Swift
> object that represents a file descriptor and don't allow references to
> escape the function, the object will be destroyed (and its resources
> reclaimed) at the latest when the function returns. In my opinion, this
> makes a "do using" statement useless for resource management.
>
> For scopes with guarantees, as Chris said, the most common pattern is to
> have a function that accepts a closure. I've seen some pretty serious
> nesting with `if let` (which are one very frequent case of scopes with
> guarantees), but other than that, I don't see lots of nesting and I've been
> pretty happy with what the language can do so far. The only thing I can
> complain about is that you can't use break/continue with the current setup.
>
> I see the discrepancy between objects, but I would say that any
> scope-based solution will often be just as hard to discover as the current
> solutions. `do using AutoreleasePool() { ... }` isn't an improvement over
> `autoreleasepool { ... }`.
>
> It's better for the lock case, but only if you agree that `do using` is
> useless for resource management. Otherwise, if your mutex itself benefits
> from being scoped, `do using lock` is probably creating/deleting a mutex,
> and you'd need to use `do using Lock(mutex) { ... }` to actually lock it
> (like with C++ mutex/lock objects), which is as discoverable as `mutex.lock
> { ... }`.
>
> Félix
>
> Le 29 déc. 2015 à 23:24:53, Trent Nadeau via swift-evolution <
> swift-evolution at swift.org> a écrit :
>
> While useful, that pattern doesn't seem to compose well. What if you need
> two locks? Would that be:
>
> lock1.withThisLockHeld {
>     lock2.withThisLockHeld {
>         // statements
>     }
> }
>
> If so, it seems like it has the "pyramid of doom" issue that prompted
> allowing `if let` to have multiple bindings.
>
> In addition to the possible indentation and vertical space issue, you need
> to look up if and how each resource type does this. I believe this is a
> general enough pattern that it deserves language support. I think an
> analogy to the current situation would be if each collection type had its
> own way to iterate (Array.forEach, Set.withEachElement, etc.) instead of
> having for-in.
>
> On Tue, Dec 29, 2015 at 11:15 PM, Chris Lattner <clattner at apple.com>
> wrote:
>
>> On Dec 29, 2015, at 8:02 PM, Trent Nadeau via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> > 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.
>> >
>> > ```swift
>> > do {
>> >     lock.enterScope()
>> >     defer { lock.exitScope() }
>> >
>> >     let file = try getFileHandle()
>> >     file.enterScope()
>> >     defer { file.exitScope() }
>> >
>> >     // statements
>> > }
>>
>> We have another pattern that types can use, which is:
>>
>> lock.withThisLockHeld {
>>   … stuff ...
>> }
>>
>> This can be done today with trailing closures.  Other examples of this
>> are “autoreleasepool” and withUnsafePointer (for other reasons).
>>
>> -Chris
>>
>>
>
>
> --
> Trent Nadeau
>  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>


-- 
Trent Nadeau
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151230/73d32199/attachment.html>


More information about the swift-evolution mailing list