Unexpected warning: 'flatMap' is deprecated

I was trying out some things and ran into a warning I don't think should be happening:

let pythagoreanTriples =
    (1...).lazy.flatMap { z in
        (1...z).lazy.flatMap { x in
            (x...z).lazy.flatMap { y in // <- Warning on this line
                (x, y, z)
    }.filter { (x: Int, y: Int, z: Int) in x * x + y * y == z * z }

// warning:'flatMap' is deprecated: Please use compactMap(_:) for the case where closure returns an optional value

Changing flatMap to compactMap gets rid of the warning, but I don't think it's right. The code works correctly both ways.

Is this a bug or am I missing something? Swift version is 5.1.3

You can use map for that final operation since it is converting y into (x, y, z).

The use of flatMap when not working with another Sequence/Collection type is deprecated since it used to also do what compactMap does.

1 Like

Ah right, that makes sense. The warning put me on the wrong track, thanks!

The type of (x...z).lazy is LazyMapSequence<(ClosedRange<Int>), Int.Type>.

LazyMapSequence defines a non-deprecated flatMap method:

func flatMap<SegmentOfResult>(
    _ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

Note that transform here must return some sort of Sequence. In your code, you return (x, y, z), which is a tuple, and tuples do not conform to Sequence. So Swift cannot use this flatMap method.

LazyMapSequence also defines a deprecated flatMap method:

func flatMap<ElementOfResult>(
    _ transform: @escaping (Element) -> ElementOfResult?
) -> LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazyMapSequence<Base, Element>, ElementOfResult?>>, ElementOfResult>

Here, transform must return an Optional of a single output element. Since Swift can implicitly promote any non-optional value to an optional value, Swift can use this version of flatMap to compile your code.

The deprecated flatMap was deprecated by SE-0187.


Thanks for the detailed explanation @mayoff, it's more clear to me now what happened exactly.