[swift-evolution] Add an ifPresent function to Optional

davesweeris at mac.com davesweeris at mac.com
Mon Mar 14 19:51:47 CDT 2016

> On Mar 14, 2016, at 5:51 PM, Dmitri Gribenko via swift-evolution <swift-evolution at swift.org> wrote:
> Optional.map returns an Optional.
> Array.map returns an Array.
> Set.map returns an Array.
> <any other collection>.map returns an Array.
> I can't say that it is not valid to think about an Optional as a tiny
> collection, but as implemented in Swift, .map() does objectively
> behave differently...
That behavior is, at least partially, because protocols don’t currently support this:
protocol CollectionType {
    typealias T
    func map<U>(transform: T->U) -> Self<U> // error: Cannot specialize non-generic type 'Self'
I *think* I remember reading on here somewhere that the intent is to change map and flatMap to return “Self<U>" pretty much as soon as the language supports it. Someone from Apple would have to confirm that, though… my memory is quite hazy on the matter.

More to the point, in terms of what you could actual do with a variable, there’s no real difference between:
var foo: [Int] = []
var foo: Int? = nil
In both cases you have to check foo's “count” so to speak, before you can safely access its element(s), otherwise the most you can do is pass it along to some other code. If the language had the features to support it, Optional could literally be defined like this:
typealias Optional<T> = Array<T where self.count <= 1>
While the syntax of how we’d interact with Optionals might change, functionally speaking, I can’t think of any difference at all. Both provide storage for a variable # of elements (only slightly variable in Optional’s case, but variable none the less), both throw equally fatal errors if you try to access elements that don’t exist, and provide quick access to those that do exist. Furthermore, within the limitation of how many “elements” an Optional can store, it’s trivial to convert between the two types:
extension Array {
    init(_ x: Element?) {
        switch x {
        case .None: self = []
        case .Some(let value): self = [value]
extension Optional {
    init(arrayLiteral elements: [Optional.Wrapped]) {
        switch elements.count {
        case 0: self = .None
        case _: self = .Some(elements[0])

All this suggests, to me anyway, that at least in this regard, they’re the same “meta type”. What’s the harm in having the API reflect that?

- Dave Sweeris

P.S. Should we be having this conversation in a different thread? I’m *really* bad about going down every rabbit hole I can find, and I don’t want to upset the mailing list by dragging them along with me...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160314/0939f13c/attachment.html>

More information about the swift-evolution mailing list