This is the first post in Swift
series. Bool
is a pretty straight forward and simple data type. Let’s look how it has been implemented.
Bool
is a value type. Hence it should be defined using a struct
. Indeed it is.
@_fixed_layout
public struct Bool {
@usableFromInline
internal var _value: Builtin.Int1
// ...
// ...
}
Here we can see the struct
has a member named _value
which is of type Builtin.Int1
which is an abstraction on Int
which uses a single bit but aligned by 8 bits.
Let’s look how the constructors are implemented. By now you might have guessed it right. We might store 0
for falsy and 1
for truthy in _value
.
@_transparent
public init() {
let zero: Int8 = 0
self._value = Builtin.trunc_Int8_Int1(zero._value)
}
The code is very much readable and we get an idea what is going on here. When we declare a Bool
variable , by default it will be falsy
.
Then we have another constructor that takes in an Int1
value, but this is not public and is for internal
use only
@usableFromInline @_transparent
internal init(_ v: Builtin.Int1) { self._value = v }
Then another constructor that takes in a Bool
type and assigns from it.
@inlinable
public init(_ value: Bool) {
self = value
}
Then we have two static random
methods out of which one takes a RandomNumberGenerator
other one uses the default SystemRandomNumberGenerator
@inlinable
public static func random<T: RandomNumberGenerator>(
using generator: inout T
) -> Bool {
return (generator.next() >> 17) & 1 == 0
}
@inlinable
public static func random() -> Bool {
var g = SystemRandomNumberGenerator()
return Bool.random(using: &g)
}
These methods allow us to write boolean expressions such as:
let flippedHeads = Bool.random()
or let flippedHeads = Bool.random(using: &myGenerator)
Then we have several extensions on Bool
which make it conform to protocols ExpressibleByBooleanLiteral
, CustomStringConvertible
, Equatable
, Hashable
, LosslessStringConvertible
Then we have the operators acting upon a Bool
.
It is this piece of code that helps us to write code like let flippedValue = !value
. You can see it is implemented as an xor operation between truthy
and current value
@_transparent
public static prefix func ! (a: Bool) -> Bool {
return Bool(Builtin.xor_Int1(a._value, true._value))
}
Then we have the &&
operation that we use on Bool
.
@_transparent
@inline(__always)
public static func && (lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows
-> Bool {
return lhs ? try rhs() : false
}
Here the implementation uses short circuit evaluation where if the first one evaluates to false
, then rhs is not at all evaluated. And the rhs uses a @autoclosure
. It helps us to write an expression and swift will generate the closure for us automatically. Hence we are able to write something like let a = flippedValue && someSlowMethod()
Here, if the flippedValue
is false
then the someSlowMethod
won’t be even invoked. And we are able to write such an expression because of the @autoclosure
signature.
Same goes with the logical or operator
@_transparent
@inline(__always)
public static func || (lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows
-> Bool {
return lhs ? true : try rhs()
}
Another thing to note is the rethrows
keyword that is being used. It tells the compiler that the ||
operation will throw only if the rhs
is an expression that throws
. Hence we wont need to wrap every ||
in try catch unless it has a throwing method in the evaluation.
And then comes my personal favourite toggle
method which was introduced in Swift 4.2.
@inlinable
public mutating func toggle() {
self = !self
}
This was quite controversial when introduced in the Swift evolution. Eventhough it is a simple method, the beauty comes in the caller side. Most often in my apps, I would have to write code to show and hide some element. It used to be
@objc func toggleSidebar() {
splitViewItems.first?.animator().isCollapsed = !splitViewItems.first?.animator().isCollapsed
}
is now replaced by
@objc func toggleSidebar() {
splitViewItems.first?.animator().isCollapsed.toggle()
}
This is much more clean and concise. It’s a joy to use toggle
This is all of the code of Bool
type as of the day I am writing this post. We have here lot of swift constructs and tricks like auto closure, rethrows, short circuit evaluation etc. Moreover now you know how the Bool
is implemented in your favourite language!
Cheers!