[swift-evolution] Request for Discussion: Setup closures

Erica Sadun erica at ericasadun.com
Fri Dec 4 15:24:09 CST 2015

PROBLEM: With many Apple-supplied classes, typical initializers fail to fully set up an instance for use.  Here's one example:

let task = NSTask()
task.launchPath = "/usr/bin/mdfind"
task.arguments = ["kMDItemDisplayName == *.playground"]
task.standardOutput = pipe

Here's another:

let questionLabel = UILabel()
questionLabel.textAlignment = .Center
questionLabel.font =  UIFont(name:"DnealianManuscript", size: 72)
questionLabel.text = currentQuestion.questionText
questionLabel.numberOfLines = 0

You end up with stodgy repetitive code that turns into a blocky hard-to-follow clump. Here are some of my complaints:
This code feels unnecessarily redundant 
This code visually stacks. The task/task/task and questionLabel/questionLabel/questionLabel blocks draw attention away from the actual set-up these lines of code are intended to do. 
The extra symbol verbiage goes against common Swift style. For example, when the context is clear, prefer .whitespaceAndNewlineCharacterSet to NSCharacterSet.whitespaceAndNewlineCharacterSet.
Further, if you have many instances to set up there's no clear way to differentiate unrelated set-up groups other than inserting whitespace gaps or building custom factory functions.

PROPOSED SOLUTION: What do you think about creating setup closures  that modify initializers and automatically introduce self-references. For example the NSTask() initialization might look something like this instead:

let task = NSTask()>>{
    launchPath = "/usr/bin/mdfind"
    arguments = ["kMDItemDisplayName == *.playground"]
    standardOutput = pipe

In this example, the braces are scoped to the instance as self, enabling the properties to entirely drop their prefixes and be grouped together for set-up.


The advantages I see are as follows:
additional setup becomes integrated into initialization
code is streamlined, a general Swift ideal
the indented scope provides a visual emphasis of the single task being addressed
allows easier top-level initialization for global values, especially for Swift playgrounds.

The disadvantages I imagine would include:
the need for a new operator to disambiguate trailing closures from setup
compiler tweaking so `self`-references within the closure work without constant copies for value types


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151204/6cacca68/attachment.html>

More information about the swift-evolution mailing list