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

BehaviorRelay is a part of RxCocoa shouldn't it be a part of RxSwift? #1502

Closed
sandeeplearner opened this Issue Nov 23, 2017 · 9 comments

Comments

Projects
None yet
4 participants
@sandeeplearner

sandeeplearner commented Nov 23, 2017

BehaviorRelay is a part of RxCocoa, shouldn't it be a part of RxSwift:

I was trying to access BehaviorRelay in my swift file, as I had already imported RxSwift. Could not access it and had no clue as to where to search for it. I finally realized that BehaviorRelay is a part of RxCocoa and not RxSwift

Expected outcome:
As all other subjects are a part of RxSwift BehaviorRelay should also be a part of RxSwift

What actually happens:
The statement that BehaviorRelay is a alternate to Variable confuses more, as Variable was a part of RxSwift. Its more instinct that BehaviorRelay must be a part of RxSwift. As documention isn't clear about it, creates a great confusion as to where to find it

RxSwift/RxCocoa/RxBlocking/RxTest version/commit

RxSwift (4.0.0)
Platform/Environment

  • iOS
  • macOS
  • tvOS
  • watchOS
  • playgrounds

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • easy, 100% repro
  • sometimes, 10%-100%
  • hard, 2% - 10%
  • extremely hard, %0 - 2%

Xcode version:

  Version 9.1 (9B55)

Installation method:

  • CocoaPods
  • Carthage
  • Git submodules

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • yes (which ones)
  • no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • just starting
  • I have a small code base
  • I have a significant code base
@kzaher

This comment has been minimized.

Show comment
Hide comment
@kzaher

kzaher Nov 26, 2017

Member

Hi @sandeeplearner ,

No, BehaviorRelay is not a "standard" concept and it's more suited for stateful environments only.

We will be moving Variable out of RxSwift and probably making it just a typealias in RxCocoa. #1501

As all other subjects are a part of RxSwift BehaviorRelay should also be a part of RxSwift

This is not a subject because it's not an observer.

Member

kzaher commented Nov 26, 2017

Hi @sandeeplearner ,

No, BehaviorRelay is not a "standard" concept and it's more suited for stateful environments only.

We will be moving Variable out of RxSwift and probably making it just a typealias in RxCocoa. #1501

As all other subjects are a part of RxSwift BehaviorRelay should also be a part of RxSwift

This is not a subject because it's not an observer.

@sandeeplearner

This comment has been minimized.

Show comment
Hide comment
@sandeeplearner

sandeeplearner Nov 27, 2017

@kzaher :

This is not a subject because it's not an observer.

Sorry am a noob in RxSwift. So did not really realize that it is a observer. I was confused by the statement that BehaviorRelay will be a alternate to Variable. I took it quite literally I thought as Variable was a subject BehaviorRelay will also be a subject. Thank you for informing

No, BehaviorRelay is not a "standard" concept and it's more suited for stateful environments only.

Sorry forgive me for my dumb question, but don't you think RxCocoa should have Rx implementation for Cocoa components only and have non-cocoa and language specific components in RxSwift? At least name is little intuitive in that way.

For example, lets consider Foundation and UIKit frameworks,
I would not go and search for UITextField in Foundation framework I know its a UIComponent hence should be a part of UIKit but on the other hand I would not look for Array in UIKit.

That way figuring out where each component of programming lies becomes easy. Variable/BehaviorRelay can be used absolutely in isolation from UI components hence thought should be a part of RxSwift.

Just a thought :)

sandeeplearner commented Nov 27, 2017

@kzaher :

This is not a subject because it's not an observer.

Sorry am a noob in RxSwift. So did not really realize that it is a observer. I was confused by the statement that BehaviorRelay will be a alternate to Variable. I took it quite literally I thought as Variable was a subject BehaviorRelay will also be a subject. Thank you for informing

No, BehaviorRelay is not a "standard" concept and it's more suited for stateful environments only.

Sorry forgive me for my dumb question, but don't you think RxCocoa should have Rx implementation for Cocoa components only and have non-cocoa and language specific components in RxSwift? At least name is little intuitive in that way.

For example, lets consider Foundation and UIKit frameworks,
I would not go and search for UITextField in Foundation framework I know its a UIComponent hence should be a part of UIKit but on the other hand I would not look for Array in UIKit.

That way figuring out where each component of programming lies becomes easy. Variable/BehaviorRelay can be used absolutely in isolation from UI components hence thought should be a part of RxSwift.

Just a thought :)

@kzaher

This comment has been minimized.

Show comment
Hide comment
@kzaher

kzaher Nov 28, 2017

Member

Hi @sandeeplearner ,

Sorry forgive me for my dumb question, but don't you think RxCocoa should have Rx implementation for Cocoa components only and have non-cocoa and language specific components in RxSwift? At least name is little intuitive in that way.

ideally, yes, I would agree with you. However there are some practical problems to consider:

  • tooling support for packaging is quite bad in Xcode (compared to intellij or android studio) -> we'll receive complaints of type, do I really need to type 3+ times import XXX just to use this, already had in past.
  • Carthage will build RxSwift additionally every time for each of the libraries inside this repo that depends on RxSwift (we've received plenty of complaints about this in the past even though this isn't an issue with the project itself)
  • We'll probably receive more complaints of this form

Could not access it and had no clue as to where to search for it.

... because we can't name those additional libraries in such a way that perfectly describes their content.

  • we were discussing separating all traits into their own library, but couldn't find any practical benefits at the time
  • at the time or writing I can't imagine somebody using *Relay server side with RxSwift or Linux and if they are using it in some mobile or desktop app, they already need to import RxCocoa, so what's the real benefit there? (maybe this will change in future)

But I never say never.

Member

kzaher commented Nov 28, 2017

Hi @sandeeplearner ,

Sorry forgive me for my dumb question, but don't you think RxCocoa should have Rx implementation for Cocoa components only and have non-cocoa and language specific components in RxSwift? At least name is little intuitive in that way.

ideally, yes, I would agree with you. However there are some practical problems to consider:

  • tooling support for packaging is quite bad in Xcode (compared to intellij or android studio) -> we'll receive complaints of type, do I really need to type 3+ times import XXX just to use this, already had in past.
  • Carthage will build RxSwift additionally every time for each of the libraries inside this repo that depends on RxSwift (we've received plenty of complaints about this in the past even though this isn't an issue with the project itself)
  • We'll probably receive more complaints of this form

Could not access it and had no clue as to where to search for it.

... because we can't name those additional libraries in such a way that perfectly describes their content.

  • we were discussing separating all traits into their own library, but couldn't find any practical benefits at the time
  • at the time or writing I can't imagine somebody using *Relay server side with RxSwift or Linux and if they are using it in some mobile or desktop app, they already need to import RxCocoa, so what's the real benefit there? (maybe this will change in future)

But I never say never.

@hmlongco

This comment has been minimized.

Show comment
Hide comment
@hmlongco

hmlongco Dec 7, 2017

Agree with sandeeplearner in that Variable was defined in RxSWift, and its replacement (if any) should also be in RxSwift.

Variable (and BehaviorRelay) are most definitely NOT UI components. Yes, you can bind them to UI components (and that binding could be in RxCocoa) but the concept can definitely be used anywhere in model and service-level code.

Further, I also take exception to simply moving Variable AND BehaviorRelay to RxCocoa. While we do import RxCocoa in our financial app, we only do so in the ViewControllers and other UI-based elements that need it.

Models, ViewModels, and Service files have all used Variable, and since they all know nothing about UI elements, those files import RxSwift ONLY. Why require modification of dozens upon dozens of source files to import yet another module that supports UI elements they shouldn't even know about?

hmlongco commented Dec 7, 2017

Agree with sandeeplearner in that Variable was defined in RxSWift, and its replacement (if any) should also be in RxSwift.

Variable (and BehaviorRelay) are most definitely NOT UI components. Yes, you can bind them to UI components (and that binding could be in RxCocoa) but the concept can definitely be used anywhere in model and service-level code.

Further, I also take exception to simply moving Variable AND BehaviorRelay to RxCocoa. While we do import RxCocoa in our financial app, we only do so in the ViewControllers and other UI-based elements that need it.

Models, ViewModels, and Service files have all used Variable, and since they all know nothing about UI elements, those files import RxSwift ONLY. Why require modification of dozens upon dozens of source files to import yet another module that supports UI elements they shouldn't even know about?

@Krisiacik

This comment has been minimized.

Show comment
Hide comment
@Krisiacik

Krisiacik Dec 11, 2017

Totaly agree with @hmlongco ..I ahve pretty much the same situation and component relatioships.
ViewModel components use RxVariables to store temporary mutable state.

Krisiacik commented Dec 11, 2017

Totaly agree with @hmlongco ..I ahve pretty much the same situation and component relatioships.
ViewModel components use RxVariables to store temporary mutable state.

@kzaher

This comment has been minimized.

Show comment
Hide comment
@kzaher

kzaher Dec 13, 2017

Member

The purest approach would be to extract relays into RxRelay framework, Driver and Signal into SharedSequence framework and remove Variable completely.

I can understand the puristic approach, and separating concepts into their own self contained frameworks with small public API, but I would like to avoid creating, maintaining, importing and using two additional micro frameworks for puristic sake without any obvious benefits.

If I were to choose where to put relays, I would definitely pick RxCocoa for now because they are stateful convenience wrappers. They don't make any sense when using RxSwift in server side environment, they aren't cross platform and are just simple wrappers that one could recreate themselves if needed without even importing RxCocoa ... any yes, I understand what are the drawbacks of that approach and I'm not pretending there aren't any compromises.

Member

kzaher commented Dec 13, 2017

The purest approach would be to extract relays into RxRelay framework, Driver and Signal into SharedSequence framework and remove Variable completely.

I can understand the puristic approach, and separating concepts into their own self contained frameworks with small public API, but I would like to avoid creating, maintaining, importing and using two additional micro frameworks for puristic sake without any obvious benefits.

If I were to choose where to put relays, I would definitely pick RxCocoa for now because they are stateful convenience wrappers. They don't make any sense when using RxSwift in server side environment, they aren't cross platform and are just simple wrappers that one could recreate themselves if needed without even importing RxCocoa ... any yes, I understand what are the drawbacks of that approach and I'm not pretending there aren't any compromises.

@hmlongco

This comment has been minimized.

Show comment
Hide comment
@hmlongco

hmlongco Dec 16, 2017

Variables and Relays may not make any sense from a purist's perspective, but many people don't approach Rx in quite that fashion. Consider...

class TokenTracker {
    let tokens = Variable([String]())
    func trackToken(_ t: String) {
        tokens.value.append(t)
    }
}

Here I have a set of tokens that I'm managing, while at the same time automatically exposing changes to that set to any observers who may be interested in those changes.

It's not Rx from the purist's perspective, but it's pretty good Swift. Note that I quite literally can not make any changes to my token list without that change being broadcast. The code's bulletproof. Add another function to remove a token, and the code's still bulletproof.

Contrast with...

class TokenTracker {
    var tokens = [String]()
    let changed = PublishSubject<Bool>()
    func trackToken(_ t: String) {
        tokens.append(t)
        changed.onNext(true)
    }
}

Not only do I have to maintain state separately, but I have to remember to explicitly fire the changed event for each and every operation. I had to write twice as much code, and it's more fragile than the original.

I could be more Rx'y, I suppose....

class TokenTracker {
    var tokens = [String]()
    let addToken = PublishSubject<String>()
    private let disposebag = DisposeBag()
    init() {
        addToken.subscribe(onNext: { [weak self] (t) in
            self?.tokens.append(t)
        })
        .disposed(by: disposebag)
    }
}

Which effectively provides the same functionality, albeit with more overhead, and with nearly 3x the code over the original version.

All of which boils down to three things:

  1. There's more than one way to use RxSwift. It's not an all or nothing approach.
  2. Variable performs a useful function that's not solely tied to driving UI controls.
  3. Swift is Swift.

Yes. The semantics differ on Swift. So what? Swift, as you may have noticed, is a different language than Java, JavaScript, C#, and the others.

I came to Swift to write less code. Not more.

hmlongco commented Dec 16, 2017

Variables and Relays may not make any sense from a purist's perspective, but many people don't approach Rx in quite that fashion. Consider...

class TokenTracker {
    let tokens = Variable([String]())
    func trackToken(_ t: String) {
        tokens.value.append(t)
    }
}

Here I have a set of tokens that I'm managing, while at the same time automatically exposing changes to that set to any observers who may be interested in those changes.

It's not Rx from the purist's perspective, but it's pretty good Swift. Note that I quite literally can not make any changes to my token list without that change being broadcast. The code's bulletproof. Add another function to remove a token, and the code's still bulletproof.

Contrast with...

class TokenTracker {
    var tokens = [String]()
    let changed = PublishSubject<Bool>()
    func trackToken(_ t: String) {
        tokens.append(t)
        changed.onNext(true)
    }
}

Not only do I have to maintain state separately, but I have to remember to explicitly fire the changed event for each and every operation. I had to write twice as much code, and it's more fragile than the original.

I could be more Rx'y, I suppose....

class TokenTracker {
    var tokens = [String]()
    let addToken = PublishSubject<String>()
    private let disposebag = DisposeBag()
    init() {
        addToken.subscribe(onNext: { [weak self] (t) in
            self?.tokens.append(t)
        })
        .disposed(by: disposebag)
    }
}

Which effectively provides the same functionality, albeit with more overhead, and with nearly 3x the code over the original version.

All of which boils down to three things:

  1. There's more than one way to use RxSwift. It's not an all or nothing approach.
  2. Variable performs a useful function that's not solely tied to driving UI controls.
  3. Swift is Swift.

Yes. The semantics differ on Swift. So what? Swift, as you may have noticed, is a different language than Java, JavaScript, C#, and the others.

I came to Swift to write less code. Not more.

@kzaher

This comment has been minimized.

Show comment
Hide comment
@kzaher

kzaher Dec 16, 2017

Member

@hmlongco

It's not Rx from the purist's perspective, but it's pretty good Swift. Note that I quite literally can not make any changes to my token list without that change being broadcast. The code's bulletproof. Add another function to remove a token, and the code's still bulletproof.

Variable wraps BehaviorSubject not PublishSubject. I'm not sure what point did you try to make.

The code's bulletproof.

No it's not. It's quite the opposite. If you call trackToken from multiple schedulers simultaneously that's undefined behavior since that's not a valid sequence (even though the program won't crash).

Please give me benefit of the doubt that I understand this subject :)))

There's more than one way to use RxSwift.

Sure, but you can always improve each of those ways somehow. I'm trying to tell you how should you use RxSwift, I'm trying to explain what is the rationale why some APIs are they way they are at the moment and also what are the tradeoffs of some other solutions we've considered.

The way to be constrictive about this discussion is to provide some new insights and tradeoffs of already considered scenarios or suggest new scenarios and enumerate their tradeoffs.

Variable performs a useful function that's not solely tied to driving UI controls.

Again, I'm not sure you've read my answers carefully. This is still a stateful environment you are describing, so yes, there are user controls somewhere near there. Chances you could use that code in server side stateless environment is 0 IMHO.

Swift is Swift.

I'm agreeing with the tautology.

Member

kzaher commented Dec 16, 2017

@hmlongco

It's not Rx from the purist's perspective, but it's pretty good Swift. Note that I quite literally can not make any changes to my token list without that change being broadcast. The code's bulletproof. Add another function to remove a token, and the code's still bulletproof.

Variable wraps BehaviorSubject not PublishSubject. I'm not sure what point did you try to make.

The code's bulletproof.

No it's not. It's quite the opposite. If you call trackToken from multiple schedulers simultaneously that's undefined behavior since that's not a valid sequence (even though the program won't crash).

Please give me benefit of the doubt that I understand this subject :)))

There's more than one way to use RxSwift.

Sure, but you can always improve each of those ways somehow. I'm trying to tell you how should you use RxSwift, I'm trying to explain what is the rationale why some APIs are they way they are at the moment and also what are the tradeoffs of some other solutions we've considered.

The way to be constrictive about this discussion is to provide some new insights and tradeoffs of already considered scenarios or suggest new scenarios and enumerate their tradeoffs.

Variable performs a useful function that's not solely tied to driving UI controls.

Again, I'm not sure you've read my answers carefully. This is still a stateful environment you are describing, so yes, there are user controls somewhere near there. Chances you could use that code in server side stateless environment is 0 IMHO.

Swift is Swift.

I'm agreeing with the tautology.

@kzaher

This comment has been minimized.

Show comment
Hide comment
@kzaher

kzaher Jun 7, 2018

Member

We'll address this in #1501 .

Member

kzaher commented Jun 7, 2018

We'll address this in #1501 .

@kzaher kzaher closed this Jun 7, 2018

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