Skip to content

Instantly share code, notes, and snippets.

@davidsteppenbeck
Last active July 27, 2021 07:08
Show Gist options
  • Save davidsteppenbeck/4c5e305cc85bd98f22291f1c6a07d799 to your computer and use it in GitHub Desktop.
Save davidsteppenbeck/4c5e305cc85bd98f22291f1c6a07d799 to your computer and use it in GitHub Desktop.
An infix operator for collections that returns the wrapped value of the optional only if the collection is not empty.
import Foundation
infix operator ???
extension Optional where Wrapped: Collection {
/// Performs a nil-coalescing operation, returning the wrapped value of an `Optional` instance
/// only if the wrapped value is not empty, otherwise returns a default value.
///
/// - Parameters:
/// - optional: An optional value.
/// - defaultValue: A value to use as a default.
static func ??? (optional: Self, defaultValue: @autoclosure () -> Wrapped) -> Wrapped {
if let wrappedValue = optional, !wrappedValue.isEmpty {
return wrappedValue
} else {
return defaultValue()
}
}
}
@Snowy1803
Copy link

defaultValue should be an @autoclosure () -> Self. If defaultValue is just a string literal, this isn’t a problem, but what if it’s an expensive function call? It should only be computed if needed, just like Optional’s ?? operator works

@davidsteppenbeck
Copy link
Author

defaultValue should be an @autoclosure () -> Self. If defaultValue is just a string literal, this isn’t a problem, but what if it’s an expensive function call? It should only be computed if needed, just like Optional’s ?? operator works

Hey Emil 👋

I actually did try to do that initially, as it is done with ?? like you said, but it results in this error:
Member operator '???' of protocol 'Collection' must have at least one argument of type 'Self'

But I agree that it would be better using a closure. Any ideas?

@Snowy1803
Copy link

Oh yeah, you'll have to put the extension on Optional where Wrapped: Collection so the left hand side can be of type Self:

import Foundation

infix operator ???

extension Optional where Wrapped: Collection {
    
    /// Performs a nil-coalescing operation, returning the wrapped value of an `Optional` instance
    /// only if the wrapped value is not empty, otherwise returns a default value.
    ///
    /// - Parameters:
    ///   - optional: An optional value.
    ///   - defaultValue: A value to use as a default.
    static func ??? (optional: Self, defaultValue: @autoclosure () -> Wrapped) -> Wrapped {
        if let wrappedValue = optional, !wrappedValue.isEmpty {
            return wrappedValue
        } else {
            return defaultValue()
        }
    }
    
}

@davidsteppenbeck
Copy link
Author

Great idea! I updated it, thanks 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment