Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

revamped rule 2.5 + updated style guide for swift 3 #8

Merged
merged 1 commit into from
Oct 7, 2016

Conversation

cezarywojcik
Copy link
Member

@cezarywojcik cezarywojcik commented Oct 6, 2016

See changes in diff.

Rule 2.5 is a major difference; other changes are mainly updating code examples to fit with Swift 3.

Two other new rules: 3.2.5 and 3.2.6 about usage of fileprivate and open.

@@ -682,24 +689,18 @@ doSomethingWithClosure() { response: NSURLResponse in
[1, 2, 3].flatMap { String($0) }
```

* **3.8.2** When listing parameters, if using a capture list and/or specifying a (non-void) return type, wrap the parameter list in parentheses. Otherwise, the parentheses can be avoided.
* **3.8.2** When listing parameters in a closure, wrap the parameter list in parentheses.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a compiler error now? If so, we don't need this rule.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, removing.

```

* **3.8.3** If specifying a closure as a type, you don’t need to wrap it in parentheses unless it is required (e.g. if the type is optional or the closure is within another closure). Always wrap the arguments in the closure in a set of parentheses - use `()` to indicate no arguments and use `Void` to indicate that nothing is returned.

```swift
let completionBlock: (success: Bool) -> Void = {
let completionBlock: (Bool) -> Void = { success in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't follow the rule from above, correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is. The rule is talking about wrapping the entire declaration in parentheses, e.g. ((Bool -> Void) instead of (Bool) -> Void.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I was talking about the parameter name before the in

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, my bad. Fixing!


```swift
struct Error: ErrorType {
struct Error: Swift.Error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like you should name this differently instead of Error. Use like MyError

Copy link
Member Author

@cezarywojcik cezarywojcik Oct 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was struggling to come up with a good name for this, since Error works so well and anything else just seems extraneous. I wish Apple had kept this as ErrorType or ErrorProtocol =.

This works just fine if you just use Swift.Error here instead however, and it lets you keep the good naming. None of the alternatives that I've considered (ErrorWithMessage, DescriptiveError, ErrorContainer, Errrrroooorrrr, etc.) seem to be as clean as just Error.

This is especially useful when you want to namespace an error type within a class. For example:

class FileLoader {

    enum Error: Swift.Error {
        // ...
    }

    // V.S.

    enum FileLoaderError: Error {
        // ...
    }

}

FileLoader.Error is a far better than FileLoader.FileLoaderError and fits more with the Swift API Guideline of avoiding needless words.

@@ -395,10 +402,10 @@ let lastName = name.lastName

* **3.1.5** Be wary of retain cycles when creating delegates/protocols for your classes; typically, these properties should be declared `weak`.

* **3.1.6** Be careful when calling `self` directly from a closure as this can cause a retain cycle - use a [capture list](https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-XID_163) when this might be the case:
* **3.1.6** Be careful when calling `self` directly from an escaping closure as this can cause a retain cycle - use a [capture list](https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-XID_163) when this might be the case:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should probably add either another rule or something hear about preferring to always use non-escaping. And probably putting a link to something that explains what the differences are.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that might be useful, but it will be out of scope for this PR.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we recommend not using [weak self] when it wouldn't be preventing a memory leak?

I think that instead of adding [weak self] everywhere just to be safe, it would be better to have people stop, pause, and think about the object graph and whether there would actually be a leak or not. By getting into the habit of thinking about cycles in object graphs, people would be more likely to notice leaks in other situations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@staguer We can address this separately since your comment is about the current rule whether we're using Swift 3 or not. Out of scope for this PR.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

@cezarywojcik cezarywojcik force-pushed the master branch 2 times, most recently from b42c17e to 6da003d Compare October 6, 2016 21:27

// NOT PREFERRED
static private let kMyPrivateNumber: Int
static private let myPrivateNumber: Int
```

* **3.2.2** The access modifier keyword should not be on a line by itself - keep it inline with what it is describing.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add something about @discardableResult and @testable being on the same or on their own lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I agree that a rule about annotations might be useful, but it's not something new for Swift 3. We can talk about it separately.

@@ -710,19 +707,20 @@ let completionBlock: () -> Void = {
let completionBlock: (() -> Void)? = nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need the = nil default value, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a local constant, you do need it. It only gets auto-initialized to nil if it is a property.

Copy link
Contributor

@drumnkyle drumnkyle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after

@@ -514,6 +521,10 @@ class Pirate {
let pirateName = "LeChuck"
```

* **3.2.5** Prefer `private` to `fileprivate` where possible.

* **3.2.6** When choosing between `public` and `open`, prefer `open` if you intend for something to be subclassable outside of a given module and `public` otherwise. Note that anything `internal` and above can be subclassed in tests by using `@testable import`, so this shouldn't be a reason to use `open`. In general, lean towards being a bit more liberal with using `open` when it comes to libraries, but a bit more conservative when it comes to a modules in a codebase such as an app where it is easy to change things in multiple modules simultaneously.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "a" before modules.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d'oh, fixed, thanks!

@staguer
Copy link

staguer commented Oct 7, 2016

LGTM

@cezarywojcik cezarywojcik merged commit 1a99e39 into linkedin:master Oct 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants