1

I'm working with Lazy Sequences of Ints:

let a = [1,2,3].lazy

I start by defining a Stream of Ints like this:

protocol Stream: LazySequenceProtocol where Element == Int {}
extension LazySequence:       Stream  where Element == Int {}
extension LazyMapSequence:    Stream  where Element == Int {}

I will be doing complex things with the streams but to demonstrate the issue I will keep things simple. I extend the stream to allow incrementing values:

extension Stream {
  func increment() -> some Stream {
    map{ value in
      return value + 1
    }
  }
}
print(Array(a.increment())) // Prints [2, 3, 4]

Note that a.increment() is a lazy function so needs to be surrounded by Array() to turn the results into an array for printing.

Also note the use of the word "some" which was introduced in Swift 5.1 to represent an opaque type and allows us to implement streams in this way - without opaque types this is not so straightforward.

And I can do more interesting things such as inserting 10 times the value after itself:

extension Stream {
  func insert10x() -> some Stream {
    flatMap{ value in
      return [value, value*10]
    }
  }
}
print(Array(a.insert10x()))             // Prints [1, 10, 2, 20, 3, 30]

And this means I can start to compose my functions in different ways:

print(Array(a.insert10x().increment())) // Prints [2, 11, 3, 21, 4, 31]
print(Array(a.increment().insert10x())) // Prints [2, 20, 3, 30, 4, 40]

All the above compiles and works as expected.

BUT... If I introduce an extra line such as the "let multiplier = 10" below then I get compiler errors:

extension Stream {
  func insert10xVersion2() -> some Stream {
    flatMap{ value in                      // Error 1
      let multiplier = 10
      return [value, value * multiplier]   // Error 2
    }
  }
}
print(Array(a.insert10xVersion2()))             // Should prints [1, 10, 2, 20, 3, 30]

Two compiler errors:

Error 1: 'flatMap' is deprecated: Please use compactMap(_:) for the case where closure returns an optional value. Use 'compactMap(_:) instead.

Error 2: Cannot convert return expression of type '[Int]' to return type 'Int?'

Both errors seem to indicate that the compiler has decided that flatMap is dealing with optionals so is encouraging use of compactMap instead.

But I would have thought this should produce identical results to the first version!

Perhaps it's a compiler bug but thought I'd check here first to see if anyone can see an issue with my code?

Cortado-J
  • 2,035
  • 2
  • 20
  • 32
  • 1
    The swift compiler can't infer the return type of multiline closures like your last example. You would have to explicitly type it as `value -> [Int]` – dan Jan 16 '20 at 21:37
  • Thanks @dan - that sorts it. I sometimes forget that when type inference doesn’t happen, that compiler errors can end up being misleading. If you want to turn into an “Answer” I’ll tick the tick to give you some points. Cheers Adahus – Cortado-J Jan 17 '20 at 09:26
  • Good discussion about this here: https://forums.swift.org/t/problems-with-closure-type-inference/11859/4 – Cortado-J Jan 17 '20 at 09:29

0 Answers0