[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
case.
## C#
C# has the `using` statement and the associated `IDisposable` interface.
```csharp
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.
```java
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
manager".
```python
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>`
"suffix".
# Detailed Design
The `Scoped` protocol shall be as follows:
```swift
public protocol Scoped {
func enterScope()
func exitScope()
}
```
The compiler statement will accept a new form for resources. For example,
```swift
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:
```swift
do {
lock.enterScope()
defer { lock.exitScope() }
let file = try getFileHandle()
file.enterScope()
defer { file.exitScope() }
// statements
}
```
# Framework Changes / Examples
As an example of some real-world classes that would be useful with
`Scoped`, from Foundation:
```swift
// Would be nice to extend the NSLocking protocol instead, but that's not
supported yet.
extension NSLock: Scoped {
func enterScope() {
self.lock()
}
func exitScope() {
self.unlock()
}
}
extension NSFileHandle: Scoped {
func enterScope() {}
func exitScope() {
self.closeFile()
}
}
```
# 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