Revisiting some old style rules with new twists.
The Rule of Lily: “When a trailing closure argument is functional, use parentheses. When it is procedural, use braces.”
myCollection.map({blah}).filter({blah}).etc myCollection.forEach {} // or dispatch_after(when, queue) {}
The consistency of style communicates whether closures return values. There’s an ongoing dispute as to whether a space should be left before trailing braces.
The Rule of Self
: “Implicit member expressions enable you to omit self
when the compiler can unambiguously infer member types. Use self
whenever a method call reflexively refers back to an instance.”
Consider the following for-loop’s where
clause. The contains
method call lacks an explicit subject. What is doing the containing? A container isn’t included as method parameter so it has to be the calling instance.
for (flagLessOne, string) in strings.enumerate() where contains( Features(rawValue: 1<<(flagLessOne + 1))) { nameArray.append(string) }
Fully qualifying the call clarifies the subject ambiguity and vastly improves readability:
for (flagLessOne, string) in strings.enumerate() where self.contains( Features(rawValue: 1<<(flagLessOne + 1))) { nameArray.append(string) }
The Rule of Conditional Binding Cascades: “Unless you’re mixing var
and let
conditional bindings, use a single if let
or if var
introduction. Add liberal whitespace as needed.”
Instead of:
if let x = x, let y = y, let z = z {blah}
use:
if let x = x, y = y, z = z {blah}
Removing extraneous let
keywords simplifies the binding cascade, and Xcode will nicely co-align these for you:
if let x = x, y = y, z = z { ...blah... }
Although cascaded bindings avoids the pre-Swift 2 “pyramids of doom”, they tend towards “constipated blocks of horror”. When faced with excess serial bindings, interleave them with spaces and comments, as in the following example, or use a sequence of guard statements.
if let // Access JSON as dictionary json = json as? NSDictionary, // Retrieve results array resultsList = json["results"] as? NSArray, // Extract first item results = resultsList.firstObject as? NSDictionary, // Extract name and price name = results["trackName"] as? String, price = results["price"] as? NSNumber { // ... blah blah ... }
The Rule of Pattern Matching Keywords: “When everything’s a binding, unify your bindings.”
Combine multiple pattern matching bindings by moving keywords out of tuples. Instead of:
if case (let x?, let y?) = myOptionalTuple { print(x, y) }
Use:
if case let (x?, y?) = myOptionalTuple { print(x, y) }
The Rule of isEmpty
: “If you’re testing a collection’s count, you’re probably doing it wrong.” Prefer isEmpty
to count == 0
.
The Rule of Void
: “Use Void
return types, not ()
.” A function returns -> Void
and not -> ()
.
func doThis() -> Void func notThis() -> ()
The Rule of !: “Every time you use an exclamation point in Swift, a kitten dies.” Wherever possible, avoid forced casts and forced unwrapping.
The Rule of Collection Creation: “Use explicit typing and empty collections.” Types to the left of the assignment, empty instances to the right.
Instead of:
var x = [String: Int]() // and var y = [Double]() var z = Set<String>() var mySet = MyOptionSet()
use
var x: [String: Int] = [:] var y: [Double] = [] var z: Set<String> = [] var mySet: MyOptionSet = []
Cite.
The “Mike Ash” colon rule: “Space to the right. No space to the left.” Or no soup for you!
Prefer
[key: value] // and struct Foo: MyProtocol
to
[key : value] struct Foo : MyProtocol
The Rules of Moving-On-From-Objective-C:
- Don’t add Objective-C-style parentheses around
if
andswitch
conditions or withreturn
keywords. - Use camel case for allTheConstants and not ALL_CAPS
- Prefer Swift constructors to legacy ones, e.g.
CGPoint(x: 1, y:1)
overCGPointMake(1, 1)
- Avoid terminal semicolons even though they compile. They make you look bad and you should feel bad for using them.
Update: Yes, I don’t just talk the talk, I walk the walk with these rules in my code:
github repo
8 Comments
Nice writeup with some good rules of engagement.
Can you share the script with the rules you use?
I did an earlier post here: https://ericasadun.com/2015/05/18/swift-alternative-lintage/
And here: https://github.com/erica/testlint
I’d add a rule to use named tuples for multiple return values:
func daytimeOnDate(date: NSDate, atCoordinate: CLLocationCoordinate2D) -> (sunrise: NSDate, sunset: NSDate)
Regarding the Rule of Void, why is returning void better than not returning anything?
func doThis() -> Void
func doThis()
In Apple’s Swift book when a function has nothing to return, they omit the ->, like the second doThis() listing in my comment.
My rule is more a comment of () vs Void for return types. See: https://ericasadun.com/2015/05/11/swift-vs-void/
[…] 作者:Erica Sadun,原文链接,原文日期:2015-11-17译者:mmoaay;校对:lfb_CD;定稿:shanks […]
In swift use 80, 100 or 120 column per line