sideeffect-io / AsyncExtensions

AsyncExtensions aims to mimic Swift Combine operators for async sequences.
MIT License
334 stars 26 forks source link

[BUG] AsyncSubject's Failure associated type conflicts with iOS 18's AsyncSequence Failure associated type #41

Closed gsl-anthonymerle closed 5 months ago

gsl-anthonymerle commented 5 months ago

Describe the bug Hi, so I updated Xcode to v16 and tried to build my app for iOS 18 but the AsyncExtensions module got some compilation errors regarding AsyncSubject's Failure associated type.

To Reproduce Steps to reproduce the behavior:

  1. Create an empty project using XCode 16
  2. Add AsyncExtensions as a package dependency
  3. Build
  4. See compilation errors

Expected behavior The application should build without any error

Screenshots Capture d’écran 2024-06-11 à 17 18 13

Environment:

Additional context After digging a bit into the code, I think that's because AsyncSubject end up defining two Failure associated type from iOS 18:

lhoward commented 5 months ago

Yes, seeing this with Swift 6.0 on Linux as well.

FabianBartels commented 5 months ago

+1

gsl-anthonymerle commented 5 months ago

Possible solutions that I'd like to explore:

  1. Rename the AsyncSubject's Failure into something else
    • This may be the easiest solution to implement
    • This changes AsyncSubject's public API, meaning that updating the package may introduce build errors if, for example, clients use current AsyncSubject.Failure type on their end. Even worse, when targeting for iOS 18 this may introduce silent bugs because AsyncSubject.Failure will not be the client's expected associatedtype anymore
  2. Use Swift Macro to define the associatedtype depending on the targeted platform
    • This will keep AsyncSubject's public API clean and unchanged ~ This may be challenging to implement because it will ask the Macro to have two behaviours depending on the current targeted platform
    • Using Swift Macro adds a non-negligible compile time overhead (passing from few seconds to build AsyncExtensions to ~30 seconds)
0xfeedface1993 commented 5 months ago

Fuck Apple!

Here is my temporary solution, which can be viewed in my branch.

Patch

#if swift(>=5.9)
public protocol AsyncSubjectable: AnyObject, AsyncSequence, Sendable where AsyncIterator: AsyncSubjectIterator {
    func send(_ element: Element)
}

public protocol AsyncSubjectTerminator {
    associatedtype Failure: Error

    func send(_ termination: Termination<Failure>)
}

public typealias AsyncSubject = AsyncSubjectable & AsyncSubjectTerminator

#elseif swift(>=5.7)
public protocol AsyncSubject<Element, Failure>: AnyObject, AsyncSequence, Sendable where AsyncIterator: AsyncSubjectIterator {
  associatedtype Failure: Error

  func send(_ element: Element)
  func send(_ termination: Termination<Failure>)
}
#else
...
#endif
gsl-anthonymerle commented 5 months ago

Thanks @0xfeedface1993! :o This works like a charm! I allowed myself to create a pull request with this change, as I was able to test it and confirmed it work and compiles on both Xcode 16 and Xcode 15 🙏

twittemb commented 5 months ago

fixed here: https://github.com/sideeffect-io/AsyncExtensions/pull/42

Thanks a lot.