For sequence elements, two operations are required:
- Check if the element is
nil or not, and - Create the
nil value of the appropriate type as the default return value if nothing is found.
For # 2, we can use the fact that enum Optional conforms to the NilLiteralConvertible protocol. For # 1, I defined the NilComparable protocol and made enum Optional match it:
protocol NilComparable { func isNil() -> Bool } extension Optional : NilComparable { func isNil() -> Bool { return self == nil } }
Now we can define a function for all sequences whose elements match up to NilComparable and NilLiteralConvertible . All option sequences fall into this category:
func firstValue<C: SequenceType where C.Generator.Element : NilComparable, C.Generator.Element : NilLiteralConvertible >(seq: C) -> C.Generator.Element { var gen = seq.generate() while let elem = gen.next() { if !elem.isNil() { return elem } } return nil
Example:
let arr = [nil, nil, Optional(1), Optional(2)]
Update: function already exists
func !=<T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool
which compares any optional value with nil , so the above protocol can be simplified to
protocol NilComparable { func !=(lhs: Self, rhs: _OptionalNilComparisonType) -> Bool } extension Optional : NilComparable { } // Already conforming
Then we can write if elem != nil { ... } instead of if !elem.isNil() { ... } in the function.
A possible flaw is that _OptionalNilComparisonType is not officially documented.
Note. I tried to declare a function as
func firstValue<C: SequenceType, E where C.Generator.Element == Optional<E> >(seq: C) -> E? {
but this actually caused the compiler to crash. I don't know if this needs to be compiled.