As much as I’d like OptionSet
s to be a type, they’re not.
public protocol OptionSet : SetAlgebra, RawRepresentable
The current implementation (via a protocol), enables API evolution. As Joe Groff pointed out to me, developers can break down a single option into multiple refined options, while still offering the original components. You can see an example of this in the following implementation, where the compound energyStar
and gentleStar
options occupy an equal footing with component bit-shifted flags:
public struct LaundryOptions: OptionSet { public static let lowWater = LaundryOptions(rawValue: 1 << 0) public static let lowHeat = LaundryOptions(rawValue: 1 << 1) public static let gentleCycle = LaundryOptions(rawValue: 1 << 2) public static let tumbleDry = LaundryOptions(rawValue: 1 << 3) public static let energyStar: LaundryOptions = [.lowWater, .lowHeat] public static let gentleStar: LaundryOptions = [.energyStar, .gentleCycle] public init(rawValue: Int) { self.rawValue = rawValue } public var rawValue: Int }
Although this design looks like you are using sets, you really aren’t. The square bracket syntax is a bit a of a cheat:
let options1: LaundryOptions = [.lowWater, .lowHeat] let options2: LaundryOptions = .energyStar let options3: LaundryOptions = [.energyStar, .lowHeat] // prints 3 for each one [options1, options2, options3].forEach { print($0.rawValue) }
When you surround an option set with brackets, you get back an option set. This means in Swift, [.foo]
is the same as .foo
.
I entered into a heated style debate today with Soroush Khanlou over option sets, specifically if it were better to make a call like accessQueue.sync(flags: [.barrier])
using or omitting the brackets.
Soroush felt that omitting the brackets produces less noise. If you can compile without the brackets, why include them?
I said “use ’em”. When you’re passing flags and a static member, let the role guide your style. When the code expects an option set, make the argument look like an option set.
The brackets clearly indicate both the argument role and creates an affordance, a specific visual indication that you can expand the set by introducing more options. Without brackets, this may not be intuitively obvious to someone less familiar with option sets.
So what do you think? Brackets? No brackets? What Swift cuisine reigns supreme?