-1
\$\begingroup\$

I am learning Swift and just had a quick question about use of parentheses. The code below runs just fine w/o using parentheses, but it certainly looks a lot cleaner using them in this instance.

So my question is: In SwiftUI, is it basic practice to use parentheses for the sake of cleanliness? Might be a silly question - but am new and eager to learn.

let currentHR = 147

let isInTarget = (currentHR >= targetLowerBound) && (currentHR <= targetUpperBound)
let isBelowTarget = (currentHR < targetLowerBound)
let isAboveTarget = (currentHR > targetUpperBound)

if (isInTarget == true) {
    print("You're right on track!")
} else if (isBelowTarget == true) {
    print("You're doing great, but to try to push it a bit!")
} else {
    print("You're on fire! Slow it down just a bit")
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ On this site is is expected that you post code from working project, with sufficient context to be reviewed. General “best practices” questions are off-topic. Compare codereview.stackexchange.com/help/dont-ask and codereview.stackexchange.com/help/how-to-ask. \$\endgroup\$ – Martin R Jan 29 at 20:12
  • \$\begingroup\$ I am not sure if this falls outside the guidelines for “best practices” questions. This isn't necessarily “purely generic, hypothetical code.” I guess it could be, but it could just as easily be from a real project... \$\endgroup\$ – Rob Jan 31 at 21:59
  • \$\begingroup\$ In that case the question author should present the purpose of that code (in the question title and body). In its present form (“So my question is: In SwiftUI, is it basic practice to use parentheses for the sake of cleanliness?”) it is a best practices question, as I see it. – It is unfortunate that even after two days the author did not reply to those concerns. \$\endgroup\$ – Martin R Feb 1 at 8:32
  • \$\begingroup\$ Sorry for the very late response - I missed these. I really appreciate everyones input and corrections, and I apologize for not correcting the title. \$\endgroup\$ – sam Feb 1 at 19:47
1
\$\begingroup\$

A few observations:

  1. When using Booleans, we would generally not use the == true test, much less the parentheses. E.g. from The Swift Programming Language: The Basics

    Boolean values are particularly useful when you work with conditional statements such as the if statement:

    if turnipsAreDelicious {
        print("Mmm, tasty turnips!")
    } else {
        print("Eww, turnips are horrible.")
    }
    

    So, in your example, you might do:

    if isInTarget {
        print("You're right on track!")
    } else if isBelowTarget {
        print("You're doing great, but to try to push it a bit!")
    } else {
        print("You're on fire! Slow it down just a bit")
    }
    

    In this case, the use of the == true would be considered unnecessary syntactic noise.

  2. Regarding the use of redundant parentheses in Swift (e.g. if (isInTarget) { ... }), they are generally omitted. To most of our eyes, including redundant parentheses does not improve readability. In fact, if one includes redundant parentheses, the code tends to feel like Swift code written by an Objective-C programmer (because these these parentheses are required by Objective-C, but not Swift).

    FWIW, linters (such as SwiftLint) will tend to warn you if you include redundant parentheses, further evidence that use of extraneous parentheses in if statements is considered an anti-pattern by many:

    enter image description here

    Needless to say, if you need parentheses, then, of course, use them. E.g.:

    if (a && b) || (c && d) { ... }
    
  3. Regarding the redundant use of parentheses in the Boolean let statements, that is more of question of personal taste and you should do whatever makes your code easiest to understand. I am sympathetic to the use of parentheses in that scenario (though I generally would not, personally).

  4. As an aside, if you are dealing with ranges of numeric values, you might consider using Range or ClosedRange type, which has lowerBound and upperBound properties, e.g.

    let targetRange = 120...180
    let currentHR = 147
    
    let isInTarget = targetRange.contains(currentHR)
    let isBelowTarget = currentHR < targetRange.lowerBound
    
    if isInTarget {
        print("You're right on track!")
    } else if isBelowTarget {
        print("You're doing great, but to try to push it a bit!")
    } else {
        print("You're on fire! Slow it down just a bit")
    }
    
\$\endgroup\$
0
-1
\$\begingroup\$

In addition: if the parentheses make it easier for you to read then of course you can use them. People who are used to other languages often will write that way, but more experienced Swift developers, and people who only know Swift, generally don't. People like what they are familiar with.

There are occasions where the swift compiler will require the use of parentheses to silence a warning about something. That's another reason to prefer to avoid parentheses when they are not required. This is also true about the use of "self." prefix and the use of semicolons. It means when you do need to use them, they stand out more, alerting you to something unusual going on.

The use of the "== true" is often seen when working with optional Bool types, and so that is another good reason to avoid using it when working with non-optional Bools.

If you are interested in writing your function more Swift-ily, then I would suggest this problem would benefit from using ranges.

For example: let targetRange: ClosedRange<UInt> = 120...180 allows you to either switch over the cases, or say targetRange.contains(...)

The cases in a switch would then be

...targetRange.lowerBound
targetRange
targetRange.upperBound...

Also it would be good practice to separate out the side effect of printing these values from the pure function of calculating them. That makes the function testable.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.