Swift: Should We Make Optionals Clearer?
Who wants to live without extensions
Optionals are great, but there are some improvements that might make code clearer and more explicit. I also want to acknowledge that in some cases you don't actually care if the value is nil or not, you just want to provide an alternate value if it is; that's usually called the null coalescing operator, but Swift doesn't currently have one.
extension Optional {
func valueOrDefault(defaultValue:@auto_closure ()->T) -> T {
return apply(self!, defaultValue())
}
var hasValue: Bool {
get { return apply(true, false) }
}
private func apply<U>(caseSome:@auto_closure ()->U,
_ caseNone:@auto_closure ()->U) -> U {
switch(self) {
case .Some:
return caseSome()
case .None:
return caseNone()
}
}
}
var s:String? = nil
//equivalent to 'if let s2 = s'
let s2 = s.valueOrDefault("alt")
//equivalent to 'if s'
if s.hasValue {
println("Has value!")
}
Instead of using the optional as a logic value directly, you can be explicit by using hasValue
. Is that an improvement?
There's also Venkat Peri's post about defining an operator :
operator infix ||| {}
@infix func |||<T> (left: T?, right: T) -> T {
if let l = left { return l }
return right
}
@infix func |||<T,V> (left: T?, right: V) -> Any {
if let l = left { return l }
return right
}
let s3 = s ||| "alternative"
I'm still on the fence about these. The design of Optional<T>
does resemble the Objective-C if(var)
style. I think this is another area where there's a tradeoff between terseness and code clarity that will only be resolved as the Swift community develops its own culture and coding standards.
Please feel free to leave your vote in the comments - would you like to see Apple add something similar to these extensions and operators, or is the current design just fine?
Update: I decided to go with the following, which you can find in my SwiftNonStandardLibrary project. I think !!
implies a relationship with the existing unwrap operator and gives us a bit cleaner way to specify an alternate value when dealing with optionals.
operator infix !! { associativity right }
@infix public func !!<T>(left: T?, right: @auto_closure ()->T) -> T {
return left ? left! : right()
}
public extension Optional {
public var hasValue: Bool {
get { return apply(true, false) }
}
private func apply<U>(caseSome:@auto_closure ()->U,
_ caseNone:@auto_closure ()->U) -> U {
switch(self) {
case .Some:
return caseSome()
case .None:
return caseNone()
}
}
}
Usage looks like this:
let name = someOptional !! "Unknown"
This blog represents my own personal opinion and is not endorsed by my employer.