Search code examples
swiftlazy-evaluationlazy-sequences

Returning lazy sequences


I have a lazy sequence I do some operations on and want to return from a function

func getSeq() -> ??? {
  let a = array.lazy
      ./* ... operations like map, filter, etc */
}

The final type of a is:

LazyMapSequence<FlattenSequence<LazyMapSequence<LazyFilterSequence<LazySequence<[[ComponentId] : ArchetypeId]>.Elements>.Elements, Zip2Sequence<Zip2Sequence<[C1], [C2]>, [C3]>>>, (C1, C2, C3)>

now how do I return a without having to specify the return type as that long type?


Solution

  • Opaque result types were created for exactly this purpose. They were added in Swift 5.1. You'll see them often in SwiftUI, where view contents are expressed as some View, meaning the result is some complex generic type (whose particular type is hidden from the user code), so long as it conforms to View.

    For your particular case here, you would need to them in conjunction with primary associated types, to express exactly what kind of elements the resulting sequence should produce, like so:

    func getSeq() -> some Sequence<Element> {
        return array.lazy
            ./* ... operations like map, filter, etc */
    }
    

    Primary associated types were only recently introduced in Swift 5.7. As far as I can tell, they're a purely compile-time feature, so they don't require any specific OS version at runtime.

    If Apple dropped support for your Mac and you can't run the necessary Xcode version for Swift 5.7, your next best bet is to do what we used to do: Use a type-eraser to erase the concrete type. For cases like yours, the standard library provides two type erasers, AnySequence and AnyCollection. This limits the type information to work with, so it might not optimize as nicely, but it works well enough.

    func getSeq() -> AnySequence<Element> {
        return AnySequence(
            array.lazy
                ./* ... operations like map, filter, etc */
        )
    }