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

send Action.events before sending events on the applied producer? #29

Closed
pteasima opened this issue Sep 22, 2016 · 2 comments
Closed

send Action.events before sending events on the applied producer? #29

pteasima opened this issue Sep 22, 2016 · 2 comments

Comments

@pteasima
Copy link

pteasima commented Sep 22, 2016

Currently, a producer returned from Action.apply() first sends an event on its observer, then it sends the same event on the action's .events signal. I wonder if this is by design and if there are any arguments against reversing the order in which the events are sent.

Consider the following example:

class RegisterViewModel {
    lazy private(set) var isRegistered: Property<Bool> = {
          Property(initial: false, then: self.register.events
                 .filter { $0 == .completed }
                 .take(first: 1)
                 .map { _ in true })
    }()
    lazy private(set) var login: Action<(),(),NoError> = {
        Action(enabledIf: self.isRegistered) {
            .empty //login request
        }
    }()
    lazy private(set) var registerAndLogin: Action<(),(),NoError> = Action { [weak self] in
         guard let `self` = self else { assertionFailure(); return .empty }
         return SignalProducer<(),NoError>.empty //register request
             .then(self.login.apply()
                   .flatMapError { _ in
                      assertionFailure("we are registered by now, so login should be enabled")
                      return  SignalProducer { observer, _ in  observer.sendInterrupted() } 
                   }
             )
    }
}

//...
//clientCode
viewModel.registerAndLogin.apply().start()

The above code fails on the assertion, because login is still disabled by the time we start the producer from login.apply(). This can be remedied by making isRegistered a MutableProperty and setting its value from .on(completed:) of the register request. However, this approach includes sideeffects and reduces the declarativeness of the code. Reversing the order in which events are sent would fix this code.

Let me know what you think about my example and also any counter examples you can think of. I wonder if it would cause trouble for other people and the way they use Actions. Thanks.

NOTE: I just want to start a discussion, I will gladly create a PR in the future.

@mdiep mdiep added the question label Sep 29, 2016
@mdiep
Copy link
Contributor

mdiep commented Sep 29, 2016

TBH, I'm not sure if there's a reason that one comes before the other. 🤔

I suspect that you'll sometimes want one order and sometimes want the other. So changing this would likely inflict pain on some users.

In this case, your isRegistered property does seem a little weird. Just looking at the events feels funny: it doesn't seem like that should be the source of truth. Presumably registering does something; it seems like the property should based on whatever that thing is.

@pteasima
Copy link
Author

Thanks for the answer. You are right that the registration flow here is weird (its still a prototype app, normally we would get back something like a token). However, this is not the first time I have encountered this problem. I generally dont like to do sideEffects in the producer returned from an action, and prefer doing this by binding against the .values or .events.map { //....

My general feeling is that if the producer "wraps" the action logic inside it, then there should be no more work done after the producer sends a terminating event (not even the internal "send the same event on the action's observer" work). However, I agree that its a breaking change which could cause trouble, so Im closing this.

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

2 participants