Skip to content

Conversation

stefanomondino
Copy link

@stefanomondino stefanomondino commented Sep 22, 2025

fixes: #367

As discussed in the issue with @FranzBusch, this is an attempt to allow the new share operator to be available on older Apple platforms (before iOS 18.0 and similar), also known as 1.0 compatibility.

Note: when referring to iOS *** I mean of course all the Apple platforms released in the same year

This comes with a couple of tradeoffs

  1. Mutex had to be replaced by ManagedCriticalState, as it's not available on 1.0
  2. Failure generic type for errors had to be replaced with a non-generic Swift.Error type.
  3. (really minor in my opinion): tests were not compiling on iOS simulators via Xcode with the .milliseconds(10) definitions (iOS 15.0 min compatibility), and I had to switch to nanoseconds. Using older iOS versions was the quickest thing to do on my end to test this scenario.

When ran on iOS 17.5 unfortunately ManagedCriticalState.withLock is crashing for some unknown-to-me reason - I know @phausler already encountered this and I didn't fully understand if there's a possible alternative solution / workaround or not.

I'm opening this here as a starting point.

Also, I was thinking if something this backport of Mutex could help, in terms of approach:
This is only iOS 16.0+ compatible (not 13.0) but this would be a huge step forward for us developers, since it's way easier to have business direction to accept 16.0 as minimum support, compared to 18.0.

This would probably require the entire library to rename 1.1 into 1.2, having 1.1 to be "intermediately" compatible with iOS 16.0 and 1.2 starting from 18.0 - I perfectly understand this is a huge change but I really think that including share (at least this single one!) it's critical for this package adoption.

UPDATE:
Requirements are

  • When using the API in 6.2 it must support proper typed throws
  • When using the API in pre 6.2 it must not be unconditionally always throwing the existental any Error aka Error type
  • When using the API in 6.2 it must funnel through the isolated variation (that is a huge performance hit if not)
  • the versioning of the framework must be 1.1 (if we land this the versioning will then be bumped beyond when requiring newer things); effectively we would be changing the baseline requirements of 1.1 to be a older OS release requirement than the just newly released macOS/iOS etc and 1.2 would then likely be for those requirements.

Additional tasks that would be extra bonus round stuff:

  • Updates to the pitch/documentation
  • Example code in the documentation showing how it is expected to work on pre 6.2

@Akazm
Copy link

Akazm commented Sep 30, 2025

As someone who had quite some issues with Swift stdlibs version constraints (Apple really has a habit of not caring at all, unfortunately), from my experience, packages like this solve this issue quite well:

https://github.com/swhitty/swift-mutex

It's comparable to the backport you mentioned in your Pull Request, but more mature.

@stefanomondino
Copy link
Author

@Akazm I think it's the same (I found it in the one you mentioned at the bottom of the readme, the author is the same).
I've mentioned the gist and not the entire library because it might be easier to integrate in a library like async-algorithms avoiding an explicit third party SPM dependency.

Copy link

@pyrtsa pyrtsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, would be really useful to have share available for a wide range of OS versions!

Here's a proposed fix for the withLock crash, and a few indent corrections.

Copy link

@pyrtsa pyrtsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More indentation corrections. 🤔

We'd avoid these if the repo had an .editorconfig file something like:

root = true

[*]
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true

@stefanomondino stefanomondino changed the title [WIP] 1.0 compatibility for share operator 1.0 compatibility for share operator Oct 7, 2025
@stefanomondino
Copy link
Author

thanks to @pyrtsa the branch is now passing tests properly on my end.
Waiting for @phausler and @FranzBusch feedback.

@stefanomondino stefanomondino requested a review from pyrtsa October 7, 2025 20:10
Copy link

@pyrtsa pyrtsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the only thing I wonder is whether we can keep typed throws interface also included under @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)?

There are a few stored properties making it a bit tricky, but I don't yet think it's impossible.

@phausler
Copy link
Member

phausler commented Oct 9, 2025

Just as a heads up, I haven't brushed over this - the implications here are pretty steep so this needs to be carefully considered. Backporting has some severe implications not just to the issues that already are addressed but to the process this package takes beyond just it being hosted here.

long/short please have patience with me while I check on a ton of other stuff (and note - those external requirements may have fallout to the proposed alternative here).

@phausler
Copy link
Member

phausler commented Oct 9, 2025

One thought that might have a better pan-out is leaving this as 1.1 but then altering 1.1 to have an earlier OS requirement and then posing a 1.2 for other algorithms.

@ph1ps
Copy link

ph1ps commented Oct 10, 2025

Having this AsyncSequence throw unconditionally is a deal breaker of this backport IMO.

You would probably need some rethrows trickery to get this working. If this doesn't work I feel like the pitch needs to be updated as well and point that out.

@phausler
Copy link
Member

@stefanomondino per the general concept of back porting share;

Here are the requirements to satisfy -

  • When using the API in 6.2 it must support proper typed throws
  • When using the API in pre 6.2 it must not be unconditionally always throwing the existental any Error aka Error type
  • When using the API in 6.2 it must funnel through the isolated variation (that is a huge performance hit if not)
  • the versioning of the framework must be 1.1 (if we land this the versioning will then be bumped beyond when requiring newer things); effectively we would be changing the baseline requirements of 1.1 to be a older OS release requirement than the just newly released macOS/iOS etc and 1.2 would then likely be for those requirements.

As I discuss more with the parties this potentially impacts this list may grow a bit - but that is a first blush at what would be required to do what you want.

@ph1ps I claim that any destruction of the Never vs any Error throwing case is a non starter for pretty much all algorithms. We have focused a lot of effort to ensure that any non throwing sequence should never require a try for iteration. Any place that doesn't happen it is a destruction of user expectation - so thank you for catching that nuance.

Generally speaking for anyone looking in the future for back ports of things - the bar is REALLY high in pretty much all maintained packages so this should NOT be viewed as a precedent to justify other back ports - they each have to be considered in their own merit, impact, and fallout (it really does pose a lot of complications for maintaining and delivering packages that are blessed as part of the Apple open source side of things and likewise for the Swift core libraries and even more so for the Swift compiler set of targets).

@phausler
Copy link
Member

Additional tasks that would be extra bonus round stuff:

  • Updates to the pitch/documentation
  • Example code in the documentation showing how it is expected to work on pre 6.2

These are not hard requirements for the author to specifically do but anyone who can pitch in that will definitely make my life easier ;)

@stefanomondino
Copy link
Author

stefanomondino commented Oct 11, 2025

Hello, I've tried to update this concept with your suggestions (I completely missed the "forced throw" thing, thank you for catching it).

I've been diving into the matter of this "backportable Failure" for a while, ending up on the forums where the idea seems to be to add a second protocol with a "new" Failure associatedtype. There seems to be some concerns by Slava Pestov about mangled names in distributed libraries (our case), but this should not be our case because - if I understood it correctly - (AsyncAlgorithms,FailableAsyncSequence.Failure) will always follow (_Concurrency,AsyncSequence.Failure) in lexicographic order.

Also, I've set 1.1 to older iOS versions so that we could run tests in both scenarios (i've tried iOS 17.5 and macos 15, they are both working).

Any feedback is welcomed. Thanks.

@stefanomondino
Copy link
Author

Also, on top of that, I don't think we are going to need anything additional documentation for older versions, because it will work as expected - if the underlying sequence never throws, the .share()version won't as well. Otherwise, as with all other sequences, any Errorwill be thrown.

@pyrtsa
Copy link

pyrtsa commented Oct 11, 2025

I think we can conditionally make it support typed throws, not just rethrows. Got a draft implementation working, but AFK right now. Will check back later tonight.

@stefanomondino
Copy link
Author

I think I've found a way as you said, but the iOS 17 crash is back. Will try again later

@stefanomondino
Copy link
Author

"Hic sunt leones" - at least for me.
I've created 1.2 version to allow 1.1 to be ported until ios 16 etc.
I understood where I was failing with the typed error and got it working, but now I'm constantly hitting a runtime error probably related to the missing next() declaration with isolation context on the AsyncIterator when I run tests on iOS 17.5 (it's available via extension only on 1.2).

If I move the next() method inside 1.1 everything works as expected but we lose the typed error on 1.2 (all errors becomes any Error)
At least it's better than forcing non-throwing sequences to handle non-existing errors like before, but still - if the point is to keep typed errors then we need something different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New 1.1 operators like .share() won't be available on older Apple platforms (eg: iOS <18)

5 participants