My problem
It often occurs while writing code that you need to assign a value of a certain type, based on the value of Boolean. To do this there are multiple ways, but the 2 most known are
1. The let’s-write-a-lot-of-code approach
let isAWildBoolean = true
// Set the value of `offSet` to a value based on the Boolean
let offSet:Int
if isAWildBoolean {
offSet = 10
} else {
offSet = 20
}
SwiftI don’t like the first approach, because it creates a bloated codebase. A better way is to use the ternary operator (also known as the inline-if).
2. The one-line-star-developer (ternary operator) approach
You specify the Boolean you want to evaluate, add a question mark, followed by the value if the Boolean is true, followed by a colon, followed by the value if the Boolean is false.
var isAWildBoolean = true
let offSet = isAWildBoolean ? 10 : 20
SwiftThis is already a big improvement. We went from 6 lines of code to 1 line …
but I have 2 issues with the ternary operator:
- Readability: People who are not familiar with this operator might be overwhelmed by the question mark – value – colon – value and just go bananas in their heads.
- Performance: The ternary operator is a real snail when it comes to compile performance. There is an outstanding issue on the Swift Bugs website about this. To give you an example of how slow it is I created 2 methods. One method uses the ternary operator, the other one just a regular if/else statement.
func returnResultWithTernaryOperator( value:Bool ) -> String {
return value ? "it's true" : "it's false"
}
func returnResultWithIfStatements( value:Bool ) -> String {
if value {
return "it's true"
}else {
return "it's false"
}
}
SwiftI’ve hooked up the Build Time Analyzer tool to check how long it takes for both methods to compile.
The method with the ternary operator takes 0.4ms to compile, and the method with the if-else statement takes 0.1ms to compile. That’s four times slower! On small codebases you won’t feel it, but our codebase for example takes 1 minute and 40 seconds to compile. So I’m in the process of removing all ternary operators (and other things that increase compile times) in our codebase.
3. My current solution
I’ve created an extension on the Boolean type that uses generics to return a value of a specific type and is also (in my opinion) more readable than the ternary operator. It looks like this.
import Foundation
extension Bool {
/// Convenience method to map the value of a Boolean to a specific Type.
///
/// - Parameters:
/// - ifTrue: The result when the Boolean is true
/// - ifFalse: The result when the Boolean is false
/// - Returns: Returns the result of a specific Type
func mapTo<T>( ifTrue:T, ifFalse:T ) -> T {
if self {
return ifTrue
} else {
return ifFalse
}
}
}
Swifthttps://gist.github.com/frederik-jacques/8efb3f0a8cbd46aa760880878a650931
At first I tried it with the ternary operator, but the ternary operator + generics, made it compile 6 times slower! So the obvious choice was to just use an if/else statement. To demonstrate that it really is this slow I’ve created 2 methods that do exactly the same thing. The only difference is that one uses a ternary operator, and the other one a regular if/else statement.
extension Bool {
func mapToTernary<T>( ifTrue:T, ifFalse:T ) -> T {
return self ? ifTrue : ifFalse
}
func mapTo<T>( ifTrue:T, ifFalse:T ) -> T {
if self {
return ifTrue
} else {
return ifFalse
}
}
}
SwiftIt’s sad you have to discard cool language features, just because they compile slower, and I’m sure these things will get fixed eventually in a next Swift update.
But still the overall result is a more readable way to express values of a different type based on a Boolean.
enum ViewState {
case loading
case empty
case list
case error
}
let isEmpty = false
let viewState:ViewState = isEmpty.mapTo( ifTrue: .empty, ifFalse: .list )
SwiftIf you have other ways of dealing with these kind of things or have other suggestions, just leave a comment and let’s have a discussion!
One Response
Would you please update your Unity – iOS tutorial for Unity 2017? Seems like it crashes with EXC_BAD_ACCESS. Thanks!