Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-8016] Optional flatMap accepts wrong kind of function parameter #50549

Open
mattneub opened this issue Jun 16, 2018 · 1 comment
Open

[SR-8016] Optional flatMap accepts wrong kind of function parameter #50549

mattneub opened this issue Jun 16, 2018 · 1 comment
Labels

Comments

@mattneub
Copy link

Previous ID SR-8016
Radar None
Original Reporter @mattneub
Type Improvement
Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Improvement, Documentation
Assignee None
Priority Medium

md5: 2f8e29b8782cc896afe928e50fa3ad9e

Issue Description:

This compiles:

            func f(s:String) -> Int { return 1 }
            _ = Optional("hello").flatMap(f)

Why? The declaration is:

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?

And the docs / comment say:

Use the `flatMap` method with a closure that returns an optional value

But `f` is not "a closure that returns an Optional value". It returns an Int, not an Optional<Int>. I would have thought we'd have to call `map`, not `flatMap`.

Basically what's going on here is that the docs are wrong, or at least very misleading. The docs seem to say that the distinction is between what kind of closure they take: one that produces an Optional, or one that does not. But that is quite false. They both accept either kind of closure. All of these expression compile just fine:

    let i : Int? = nil
    let result1 = i.map {_ in "hello"} // map, closure produces nonOptional
    let result2 = i.flatMap {_ in "hello"} // flatMap, closure produces nonOptional
    let result3 = i.map {_ in Optional("hello") } // map, closure produces Optional
    let result4 = i.flatMap {_ in Optional("hello") } // flatMap, closure produces Optional

Okay, so what's the actual difference? It's what `flatMap` does just in case the closure does produce an Optional: it unwraps it, thus preventing a doubly-wrapped Optional:

    let i : Int? = nil
    let result1 = i.map {_ in "hello"} // String?
    let result2 = i.flatMap {_ in "hello"} // String?
    let result3 = i.map {_ in Optional("hello") } // String?? // double-wrapped
    let result4 = i.flatMap {_ in Optional("hello") } // String? // not double-wrapped

Well, the docs should say that — and they don't.

@belkadan
Copy link
Contributor

This is one of the reasons flatMap got renamed to compactMap.

What's going on here is that values implicitly convert to optionals. That's it. That means that if I have a closure that returns a value of type T, it can convert to a closure that returns a value of type T?. There's nothing special about using compactMap here; it'll just immediately unpack the value. I guess that could go in the docs for compactMap if it isn't there already?

cc @natecook1000

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants