-
Notifications
You must be signed in to change notification settings - Fork 37
AsyncThrowingStream instead of custom type #204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks! If you have some time I would love to better understand what issues you were facing and what about KMP-NativeCoroutines is solving these issues better than Skie.
I am all for a simpler approach/implementation. But in this case the custom implementation does have a purpose.
As described in the docs
This behaviour doesn't match with the expected behaviour in Kotlin. Basically the call to
Yeah, not ideal. But not too big of a problem since
The locks are indeed to make sure that the callbacks from Kotlin will never run concurrently. |
Thanks for the detailed response!
I have trouble with code that could, even if it is theoretical contains a fatal error. So when our Android developer proposed this library I could not understand why the fatal error was needed. This intrigued me and I explored if
I added docs explaining this and added the buffer policy as a parameter so it could be chosen. If Kotlin does not have a way to continue besides throwing away results then this implementation adds that.
|
The thing is that Kotlin doesn't throw away (of buffer) values unless a consumer decides to do so. With
If you open the sample project in Xcode you can run the integrations tests from there, or using the following command:
|
Let me try grasping what you are saying and understand the test more. |
I adjusted the test KMP-NativeCoroutines/sample/Async/AsyncSequenceIntegrationTests.swift to prove that that In my opinion these changes align with Swift’s AsyncStream behaviour while preserving the expected Kotlin Flow semantics. Would love to hear your thoughts on this, and @mattmassicotte’s perspective as well. I discussed this here https://bsky.app/profile/doozmen.bsky.social/post/3lj5gdxsuxs27 and to my knowledge there are no downsides to this simplified code. Could you let me know what I should do to be able to merge it? Thanks for the thorough and very interesting feedback sofar! |
Sorry about the confusion, but we don't need to prove the buffering behaviour.
The challenge here is in preserving the Kotlin behaviour. In Kotlin you Since the val flow = flow {
var i = 0
while (true) {
emit(i++)
}
} If we would flow.collect {
delay(1.seconds)
println("Collected $it")
} We are always emitting a single value every second (even if we were to switch the To bridge from Kotlin to Swift the library starts a Since Right now this is solved by waiting for the call to
This line is the important part of the test.
I am happy to accept simplifications, but they need to preserve this "back pressure" behaviour. |
Writing this made me realise that we could actually make it match 100%. |
Sorry about my delayed response and question. It is a topic with very much knowledge needed from behind the scenes. I can see you put a lot of thinking in it and my thanks for that. On the Swift side of things I am worried about this behaviour and disabling. I cannot yet quite grasp why it is needed. I will ask @ktoso to have a look if he has time as this is a bit to complex for me. Maybe I wrongfully trust the normal |
I'm not sure how to continue. I made this pull request as I wanted to have the expected behaviour on the swift side. All the tests pass if I test for the output. The output of the stream. I fail to understand why there is a need to mimic the kotlin behaviour in the swift interface. It should at least in my opinion react as swift expect. I showed that even if the consuming thread blocks that kotlin can continue yielding values into the To do this I was able to remove fatalErrors from the code and have a simplified implementation. We are also using this implementation in our production code. I however do understand that I lack some domain knowledge about the Kotlin part and you explained it very well. But I'm just unsure why the mimic of Kotlin behaviour in a swift interface is needed? I challenge even the need for this indeed. I made the PR as the current implementation made me doubt using the library as I failed to understand why a simple |
What exactly is it that isn't working as expected?
It's not just about the output of the stream.
The whole point of the library is to be able to use a Kotlin
Please provide details on what currently doesn't react the way Swift expects.
This is the whole point. That's not how
I am not saying you can't use it like that. I am just saying that by doing this you are possibly creating a huge buffer, or dropping values, which isn't expected behaviour.
Because you are effectively calling
I am afraid we won't be able to merge this, unless we can preserve the current behaviour. |
Ok so we say the same thing but in text we do not understand each other. If possible we could have a call about this? We need this in our production app that serves al lot of clients of Mediahuis.
You respond:
As you can see the default behaviour of async streams is already to solve the issue you are coding agains in a too complicated way with fatal errors including. The buffer policy is exactly to cover the use case you describe with the flow collect to follow. So I will need this behaviour to be consistent. I do not like libraries with fatal errors trying to avoid a problem that do not exist. You are off course fee to close this pr. Please do as then I stop hoping and we can make the discussion to move away from this otherwise beautiful library. Thanks again for the time and effort but if needed I think we should agree to disagree unfortunately. |
The test proves that you never drop values. The huge buffer is normally not a problem and can be tuned via a setting. |
I made this merge request as I can prove that the current behaviour is wrong and does not work well with a large scale app that relies on streams to be piped together. The buffer is needed and has to work as expected. The current implementation tries to forcefully move away from the standard buffer behaviour causing our app to not function. So I'm trying to tell you I really think it is wrong to bypass the buffer in order to preserve a behaviour that is kotlin related and should not be preserved. Sorry again I really know these reviews take time and effort but this can be closed then as you suggest. But we cannot use your library then. I did not close it my self as I still hope we can resolve this? |
It isn't. You have removed the test logic that is supposed to test this behaviour.
It's a problem because that's not how a
You didn't provide any errors, samples or the like that prove the current behaviour is wrong. I am going to close this now as I don't believe what you are trying to achieve is possible while preserving the expected behaviour. Feel free to open an issue if you have concrete details about a use case that currently doesn't work. |
I had a look at your super library and it solved many issues compared to Skie. I had some trouble understanding the asyncSequence as I did not understand why AsyncThrowingStream could not be used directly. So I tried and came up with this solution that at least to me is simpler. Would you consider merging it?
It removes the need for the custom type
NativeFlowAsyncSequence
in favor or theAsyncThrowingStream
so this would be breaking. But it keeps the use in a for try await in ... loop so I did not have to alter the tests for them to work.I added a lock although I think you can debate as the closure of
AsyncThrowingStream
is in Swifts structured concurrency that it is safe to remove it. It does not harm the structured concurrency so I kept it as I do not know if it is needed for the Kotlin part.