nicklockwood / SwiftFormat

A command-line tool and Xcode Extension for formatting Swift code
MIT License
7.77k stars 629 forks source link

Rule Request: Remove redundant parenthesis from closures #1537

Closed rogerluan closed 10 months ago

rogerluan commented 10 months ago

I did my research :)

New rule request

This new rule would remove redundant parenthesis from closures, as it's a lot cleaner. See examples below:

What would trigger

let filteredResults = array.filter({ $0.isValid })
[1, 2].map({ $0 + 1 })
[1, 2].map({ $0 + 1 }).forEach({ print($0) })
[1, 2].map({ $0 + 1 })
  .forEach({ print($0) })
[1, 2].map { $0 + 1 }
  .map({ $0 + 2 })
  .map { $0 + 3 }
[1, 2].map({ $0 + 1 })
  .map { $0 + 2 }
  .map({ $0 + 3 })

What wouldn't trigger

// Swift Syntax doesn't allow us to remove the parenthesis in this case
guard let filteredResults = array.filter({ $0.isValid }) else { return }
// Swift Syntax doesn't allow us to remove the parenthesis in this case
if let filteredResults = array.filter({ $0.isValid }) {
    print(filteredResults)
}
guard let validElement = array.first(where: { $0.isValid }) else { return }
let filteredResults = array.filter { $0.isValid }
[1, 2].map { $0 + 1 }
[1, 2].reduce(0) { $0 + $1 }
[1, 2].map { number in
 number + 1 
}
let isEmpty = [1, 2].isEmpty()
UIView.animateWithDuration(0.3, animations: {
   self.disableInteractionRightView.alpha = 0
}, completion: { _ in
   ()
})

I believe there's a consensus that this is the expected way to write Swifty code, but I could be wrong. In fact I was very surprised that SwiftLint doesn't support this already. I'm curious to hear other opinions.

nicklockwood commented 10 months ago

Does the redundantParens rule not already do this?

rogerluan commented 10 months ago

Nope @nicklockwood 😢 it's not a covered use case/example in the docs, and I also tested and it doesn't modify my code

nicklockwood commented 10 months ago

@rogerluan oh sorry you're right - I was actually thinking of the trailingClosures rule.

I just tested it with all your examples and it seems to work (it's also enabled by default).

rogerluan commented 10 months ago

Oooh. I've explicitly disable trailing closures for some reason, I can't remember why now. I'll test it and try to remember why I disabled it as it might've been some bug 😅 I'll report back. Thanks for the help!

rogerluan commented 10 months ago

Ah, I remembered. In one of the projects I worked on, there was a overloaded function that used to cause issues, so I disabled this rule. It was weird, but an overview of the issue would be:

The issue was that due to some poor API design those two overloaded functions were only differing in the name of the closure argument IIRC (can't remember the details or give concrete examples tbh).

I don't think that is an issue that SwiftFormat should resolve haha and I see no reason to not enable this rule in all other projects :) Thanks for pointing this to me! We can close this issue 🚀

nicklockwood commented 10 months ago

@rogerluan this was actually a known issue with the rule, which was fixed in a later version by limiting it to only anonymous closure arguments (from the known issues section of the README):

The trailingClosures rule can generate ambiguous code if a function has multiple optional closure arguments, or if multiple functions have signatures differing only by the name of the closure argument. For this reason, the rule is limited to anonymous closure arguments by default. You can use the --trailingclosures and --nevertrailing arguments to explicitly opt in or out of trailing closure support for specific functions.

So I think it should be safe to re-enable it for your project now.

rogerluan commented 10 months ago

That's great to hear!! 🤩 It was indeed a long time ago and I didn't realize this has been fixed since then 😁

Thank you once again!