I ran into this when I was playing around with an OptionSet. Take this sample OptionSet
from the documentation:
struct ShippingOptions: OptionSet {
let rawValue: Int
static let nextDay = ShippingOptions(rawValue: 1 << 0)
static let secondDay = ShippingOptions(rawValue: 1 << 1)
static let priority = ShippingOptions(rawValue: 1 << 2)
static let standard = ShippingOptions(rawValue: 1 << 3)
static let express: ShippingOptions = [.nextDay, .secondDay]
static let all: ShippingOptions = [.express, .priority, .standard]
}
You can use its conformance to ExpressibleByArrayLiteral
(which comes from OptionSet
, which conforms to SetAlegrba
, which conforms to it) to compose options:
func f(singleArg: ShippingOptions) {
print(type(of: singleArg), singleArg, singleArg == .express)
// prints `ShippingOptions ShippingOptions(rawValue: 3) true`
}
f(singleArg: [.nextDay, .secondDay])
Even though var args are similar to an array literal syntax, they're not an array literal. The elements passed to a T...
are always assembled together into an Array<T>
, bypassing any conformance to ExpressibleByArrayLiteral
. That leads to this understandable, but undesirable result:
func f(optionSetVarArgs: ShippingOptions...) {
print(type(of: optionSetVarArgs), optionSetVarArgs)
// prints `Array<ShippingOptions> [ShippingOptions(rawValue: 1), ShippingOptions(rawValue: 2)]
`
}
f(optionSetVarArgs: .nextDay, .secondDay)
You can workaround this by passing the ShippingOptions...
value through the SetAlgrebra.init<S>(S)
initializer: ShippingOptions(optionSetVarArgs)
OptionSet
is a curious case, in that's its a type that models both individual values, and a collection of them, all under one roof.
Even if varargs constructed values through ExpressibleByArrayLiteral
conformances, you couldn't really use it to construct var args that were a Set<T>
. How would the compiler know you want a Set
and not an Array
?