Snippets
Capture Lists for Local Functions
- Proposal: SE-00XX
- Authors: Alex Lynch
- Review Manager: TBD
- Status: Awaiting implementation
Introduction
This proposal adds capture list semantics to local functions identical to those available for closures.
Swift-evolution thread: Making capturing semantics of local
Motivation
There is a feature disparity in swift 4 between local functions and closures (here known collectively as subroutines). In workflows that rely heavily on subroutines the difference between the two with regard to capture semantics is usually discovered first by painful mistake. Thereafter the programmer must make his choice between the two forms not based purely on expressiveness, or even style, but often perforce, based on the requirement to hold references other-than-strongly.
Example:
class A {
func regularFunc() {
func subrutineWithStrongRef() {
self.bar()
}
let subrutineWithWeakRef = { [weak self] () -> Void in
if let this = self {
self?.bar()
}
}
}
...
}
In the example above, the programmer intends to hold strong reference to self
in subrutineWithStrongRef
. This subrutine could be expressed either with a local function or a closure. However in subrutineWithWeakRef
the programmer intends to hold a weak reference to self
. At present, the programer has no choice but to select a closure, even if the use case would make a local function more expressive or easier to read.
Proposed solution
This proposal adds capture list syntax to local functions. The above example would thus be rewritten as:
class A {
func regularFunc() {
func subrutineWithStrongRef() {
self.bar()
}
func subrutineWithWeakRef() -> Void { [weak self] in
if let this = self {
self?.bar()
}
}
}
...
}
Detailed design
The existing grammar for capture lists is to be reused as an optional addition to the local function grammar. This is expected to be merely a syntactic addition which is compiled into the same form as capture lists for closures.
Source compatibility
The proposed feature follows the standard of progressive disclosure within swift. All Swift 3 and Swift 4 code will continue to compile and run as expected. No migration is needed.
Effect on ABI stability
The proposed change will have little to no effect on the ABI.
-- Real talk; I'm not sure yet if there will be any change. The compiler supports capture lists for closures, but does it handle closures and local functions differently in any meaningful way? Not sure yet. This section will be rewritten after the reference implementation of the feature.
Effect on API resilience
The proposed feature by definition has no effect on API. It is a modification to local functions which are visible only in the containing function scope.
Alternatives considered
Alternatives to the proposed solution are twofold. The first is to do nothing and live with the current feature disparity between local functions and closures. The second is alternative syntax for local function capture lists. The following forms were considered:
class A {
func regularFunc() {
// capture list before the curly brace
func subrutineWithWeakRef() -> Void [weak self] {
if let this = self {
self?.bar()
}
}
// capture list after curly brace but without 'in'
func subrutineWithWeakRef() -> Void { [weak self]
if let this = self {
self?.bar()
}
}
}
...
}
The first form was rejected as introducing a wholly new syntactical form at no benefit in clarity.
The second form was rejected as a confusing deviation from what is otherwise an immediately familiar adoption of closure capture list syntax.
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.