`compact` and `compactValues`

In the review thread SE-0218 — Introduce compactMapValues to Dictionary there was a discussion about compact and compactMap. I posted a comment earlier this morning demonstrating how these could be implemented using existing language features with the Unwrappable protocol discussed in Introducing `Unwrappable`, a biased unwrapping protocol.

A protocol like that should be debated on its own merit of course, but it's worth pointing out that it would enable algorithms like these to be implemented today in a way that would work over types other than Optional (such as Result).

protocol Unwrappable {
    associatedtype Wrapped
    func unwrap() -> Wrapped?
}
extension Optional: Unwrappable {
    func unwrap() -> Wrapped? {
        return self
    }
}
extension Array where Element: Unwrappable {
    func compact() -> [Element.Wrapped] {
        return compactMap { $0.unwrap() }
    }
}
extension Dictionary where Value: Unwrappable {
    func comactValues() -> [Key: Value.Wrapped] {
        let result = lazy.compactMap { keyValue -> (Key, Value.Wrapped)? in
            guard let value = keyValue.value.unwrap() else {
                return nil
            }
            return (keyValue.key, value)
        }
        return Dictionary<Key, Value.Wrapped>(uniqueKeysWithValues: result)
    }
}
let array: [Int?] = [42, nil, 42]
let compactArray = array.compact()
let dictionary: [Int: String?] = [42: "42", 43: nil, 44: "44"]
let compactDictionary = dictionary.comactValues()

The review thread is not the appropriate place to continue the discussion of these methods so let's move the conversation here.

1 Like

In the review thread @xwu commented:

I replied: wouldn't _Unwrappable: Unwrappable be a viable workaround for that issue while allowing other types to conform to Unwrappable?

Setting all else aside, I think it would be extremely strange to have a public method on Optional called unwrap that doesn't actually unwrap the optional.

2 Likes

It would be, sure, but the Unwrappable protocol in the link is orthogonal to the topic of working around the lack of parametric extensions. For that, you need a protocol to which only Optional conforms: this is possible with or without the proposal you link to, it's still necessary with or without it, and _Unwrappable as you name it would work around the problem here (lack of parametric extensions) whether or not it refines Unwrappable. Therefore, I think discussion about what you're linking to should be separate from the discussion about compactValues and whether to wait for parametric extensions or work around them--which is in turn distinct from compactMapValues.

I just adopted the syntax used in that thread. I would expect a very healthy round of bike shedding on the exact names were a proposal for this to make it to review.

1 Like

This makes sense to me for the most part. That said, the thread linked above is relevant to the degree that people want a compact family of methods that work with types other than Optional. I am not advocating for that, just trying to establish a framework for discussion. I would like to see the pros and cons of each approach discussed.

Sure, it can be very valuable to compare approaches. I just wanted to clarify for all participants that indeed Unwrappable as proposed in that link is not equivalent to the _Unwrappable workaround for parametric extensions and cannot be used as such.