Skip to content
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

Combine interoperability #34

Closed
ilijapuaca opened this issue Jul 22, 2019 · 4 comments
Closed

Combine interoperability #34

ilijapuaca opened this issue Jul 22, 2019 · 4 comments

Comments

@ilijapuaca
Copy link

First of all, I'd like to say I'm glad I ran into this repo, as I myself had the exact same idea and started implementing the exact same thing! As you guys seem to have solid groundwork set up already, I think that my effort is better placed in this repo. I'll be picking up a few operators and getting to work on them asap.

One of the ideas I had for my implementation (I named it PreCombine :)), was that native implementation of Combine would be used whenever possible (iOS13+, macOS10.15+). I think that it's safe to say that Combine will outperform any 3rd-party implementation out there by a good margin, especially looking at some of the benchmarks out there, and that projects such as this one are only there to bridge the gap and allow us to use frameworks of the future today.

It'll be ages before many production-level apps can drop backward compatibility and support iOS13+ for an example, but many users will definitely be upgrading their device OS much before that, so having those devices run Combine instead would (almost surely) be a performance gain, and potentially avoid a few bugs sneaking in (hopefully that won't be the case regardless :)).

With that said, what I was thinking about implementation-wise was something along the lines of:

#if combineAvailable

import Combine

typealias Publisher = Combine.Publisher

#else

/// Declares that a type can transmit a sequence of values over time.
///
/// There are four kinds of messages:
///     subscription - A connection between `Publisher` and `Subscriber`.
///     value - An element in the sequence.
///     error - The sequence ended with an error (`.failure(e)`).
///     complete - The sequence ended successfully (`.finished`).
///
/// Both `.failure` and `.finished` are terminal messages.
///
/// You can summarize these possibilities with a regular expression:
///   value*(error|finished)?
///
/// Every `Publisher` must adhere to this contract.
public protocol Publisher {

    /// The kind of values published by this publisher.
    associatedtype Output

    /// The kind of errors this publisher might publish.
    ///
    /// Use `Never` if this `Publisher` does not publish errors.
    associatedtype Failure: Error

    /// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
    ///
    /// - SeeAlso: `subscribe(_:)`
    /// - Parameters:
    ///     - subscriber: The subscriber to attach to this `Publisher`.
    ///                   once attached it can begin to receive values.
    func receive<S>(subscriber: S) where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input

}

#endif

where combineAvailable would simply be a flag set like so (DEBUG flag is debatable):

#if canImport(Combine) && !DEBUG
let combineAvailable = true
#else
let combineAvailable = false
#endif

This could obviously be more elaborate, in order to avoid boilerplate code in each top-level object implementation, but I hope you get the point. What do you guys think?

On a side-note, is there Slack organization or anything alike set up somewhere? It could be helpful seeing that many things are still up in the air, and discussing those there could likely be more efficient and keep issue list clean(er).

@broadwaylamb
Copy link
Member

broadwaylamb commented Jul 22, 2019

Hi @ilijapuaca!

projects such as this one are only there to bridge the gap and allow us to use frameworks of the future today

Not really, the first goal I had in mind when starting this project was to provide a compatible implementation for Linux so it could be used in server-side Swift development.

having those devices run Combine instead would (almost surely) be a performance gain

Being able to leverage Apple's Combine whenever it is available would indeed be great, but the thing is that clients who link against the latest SDK (which includes Combine, hence canImport(Combine) evaluates to true) but back-deploy to older OS versions without Combine are forced by the compiler to perform runtime checks like if #available(iOS 13.0) to actually use any of those Combine APIs. Conditional compilation that you propose to use is simply not enough.

On a side-note, is there Slack organization or anything alike set up somewhere? It could be helpful seeing that many things are still up in the air, and discussing those there could likely be more efficient and keep issue list clean(er).

No, there's no Slack organization. There has been no need, since there are only two active contributors right now. We use GitHub Projects to track development.

@spadafiva
Copy link
Collaborator

I think it would be useful to have a slack channel. I'm currently on the ios-developers.io slack as spadafiva if you hairy to be on there.

I'm looking forward to working with you.

-Joe

@ilijapuaca
Copy link
Author

projects such as this one are only there to bridge the gap and allow us to use frameworks of the future today

Not really, the first goal I had in mind when starting this project was to provide a compatible implementation for Linux so it could be used in server-side Swift development.

I keep forgetting that they didn't make Combine available on Linux (did you find any source about why this is the case?), I assume they'll do it at some point but that's a good point, there's definitely some value there.

having those devices run Combine instead would (almost surely) be a performance gain

Being able to leverage Apple's Combine whenever it is available would indeed be great, but the thing is that clients who link against the latest SDK (which includes Combine, hence canImport(Combine) evaluates to true) but back-deploy to older OS versions without Combine are forced by the compiler to perform runtime checks like if #available(iOS 13.0) to actually use any of those Combine APIs. Conditional compilation that you propose to use is simply not enough.

I see... I haven't tried this myself, and that would indeed be annoying to do. Do you see any other way in which this could be achieved while hiding the implementation details from developer?

@spadafiva I tried joining the workspace, but I'm getting error on their website, I assume something is broken. I'll jump on there once they fix it. Perhaps we can start a private channel on there?

@broadwaylamb
Copy link
Member

I've created a Slack workspace.

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

No branches or pull requests

3 participants