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

Trent Nadeau tanadeau at gmail.com
Tue Dec 29 22:02:59 CST 2015

# Introduction

Add a new `Scoped` protocol and enhance the do statement to automatically
call enter/exit actions on resources.

# Motivation

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.

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.

# Language Survey

At least three major languages have widely used statements for this use

## C#

C# has the `using` statement and the associated `IDisposable` interface.

using (StreamReader sr = new StreamReader(filename)) {
    txt = sr.ReadToEnd();

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.

## Java

Java has try-with-resources and the associated `AutoCloseable` interface.

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();

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.

## Python

Python has with `with` statement and the associated `__enter__` and
`__exit__` special methods that classes may implement to become a "context

with lock, open(path) as my_file:
    contents = my_file.read()
    # use contents

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.

# Proposed Solution

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.

The `do` statement will be extended to allow a new `using <resources>`

# Detailed Design

The `Scoped` protocol shall be as follows:

public protocol Scoped {
    func enterScope()
    func exitScope()

The compiler statement will accept a new form for resources. For example,

do using lock, let file = try getFileHandle() {
    // statements

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.

The above example would be syntactic sugar for the following:

do {
    defer { lock.exitScope() }

    let file = try getFileHandle()
    defer { file.exitScope() }

    // statements

# Framework Changes / Examples

As an example of some real-world classes that would be useful with
`Scoped`, from Foundation:

// Would be nice to extend the NSLocking protocol instead, but that's not
supported yet.
extension NSLock: Scoped {
    func enterScope() {

    func exitScope() {

extension NSFileHandle: Scoped {
    func enterScope() {}

    func exitScope() {

# Questions and Concerns
 * Bikeshedding protocol naming and scoping syntax
 * Should the enter and exit actions be allowed to throw errors?

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

More information about the swift-evolution mailing list