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

Mapping RAC2 hot signals to RAC3 Signal #1930

Closed
ColinEberhardt opened this issue Apr 22, 2015 · 16 comments
Closed

Mapping RAC2 hot signals to RAC3 Signal #1930

ColinEberhardt opened this issue Apr 22, 2015 · 16 comments

Comments

@ColinEberhardt
Copy link

I'm trying to map between RAC2 and RAC3 concepts, most of which seem to make sense. The one that I am struggling with is the mapping of hot signals.

The ObjC Bridging API allows you to construct a SignalProducer from a RACSignal, however it does not have an API method for constructing a Signal from a RACSignal.

As a result, any RAC2 signal is bridged to a SignalProducer and as such becomes a cold signal. Personally I consider signals derived from UI control to be hot, however I know that this is debatable.

This doesn't stop me getting the job done, I can certainly construct a SignalProducer in this case:

extension UITextField {
  func rac_textSignalProducer() -> SignalProducer<String, NSError> {
    return
      self.rac_textSignal().toSignalProducer()
        |> map { $0 as! String }
  }
}

And this works just fine for my purposes, but it does still leave me wondering how to bridge hot signals from RACSignal to Signal?

@michaelmcguire
Copy link

I had a similar question. It seems like the signals from UI controls should be "hot" or a Signal but using that type limits some of the operators you can use. Perhaps the assumption that UI controls should be 'hot' is incorrect.

@ColinEberhardt
Copy link
Author

Interesting, I've just read that thread. I'm glad that @neilpa is in agreement that signals emitted by UI Controls are 'hot' and hence should be modelled as a 'Signal'.

However, as you mentioned there are quite a few operations that can be applied to SignalProducers that I would naturally want to apply to signals.

For example on, (yeah, I know, side-effects are probably bad!), or flatMap, where I might want to trigged a network request based on some user input, where the UI controls signal is mapped to a signal producer that performs the network request (and the flattened).

I went down a similar route, implementing a few extra operations on Signal, but then switched to using SwignalProducer which has the whole 'vocabulary' available to it.

@neilpa
Copy link
Member

neilpa commented Apr 23, 2015

but it does still leave me wondering how to bridge hot signals from RACSignal to Signal?

You can't, but this should be less of an issue once the UIKit/AppKit extensions are updated to use the new APIs directly. That work hasn't happened yet because the new API was in-flux until recently.

For example on

The equivalent of this for hot Signals is to just observe events. The purpose of on is to attach side effects on a SignalProducer without starting the underlying work at the call-site.

or flatMap, where I might want to trigged a network request based on some user input

Generally you'll want to use an Action for this which is a lot better than the old RACCommand.

@ColinEberhardt
Copy link
Author

Thanks for the feedback. I'm familiar with the general concept of commands. Although with the example I am considering I don't feel that they are appropriate.

As an example, I have a text field where I want to provide suggestions as the user types. This requires an API request.

To my mind, the text input becomes a signal, which is throttled then flatMapped with a signal producer that represents the API request.

Personally I don't feel that actions / commands are the correct model for a text field's text.

@neilpa
Copy link
Member

neilpa commented Apr 26, 2015

text input becomes a signal, which is throttled then flatMapped with a signal producer that represents the API request.

This is what I'm suggesting too where Action encapsulates the mapping from input to SignalProducer via its apply method. However, I now realize my suggestion has the exact problem you're describing. There's no way to promote the inner producer values into the outer signal's stream. To allow for this join would need to defined on signal-of-producers.

@OscarSwanros
Copy link

@ColinEberhardt How would you convert the NSError param to a NoError one?

extension UITextField {
    func rac_textSignalProducer() -> SignalProducer<String, NoError> {
        return
            self.rac_textSignal().toSignalProducer()
                |> map { $0 as! String }
                |> mapError { $0 as! NoError }
    }
}

Which fails with Cast from 'NSError' to unrelated type 'NoError' always fails.

Any ideas on how to implement this? I know you can't instantiate a NoError, which leaves me wondering.

@ikesyo
Copy link
Member

ikesyo commented Apr 30, 2015

@OscarSwanros How about the following: |> catch { _ in SignalProducer<String, NoError>.empty }

@OscarSwanros
Copy link

It did work, thanks!

@ColinEberhardt
Copy link
Author

@OscarSwanros rather than cast to NoError cant you just return one regardless?

@OscarSwanros
Copy link

Yes, that's what I ended up doing.

@jspahrsummers
Copy link
Member

I like @neilpa's suggestion above:

To allow for this join would need to defined on signal-of-producers.

This doesn't really cause problems in the same way that join over signal-of-signals does, so I think we should offer it to help bridge the gap.

@neilpa
Copy link
Member

neilpa commented May 4, 2015

This doesn't really cause problems in the same way that join over signal-of-signals does, so I think we should offer it to help bridge the gap.

And even for signal-of-signals, join is mostly a problem for Concat. Otherwise Merge and Latest can still behave sensibly if the inner signals have already completed.

@jspahrsummers
Copy link
Member

@neilpa Since Signals send Interrupted if observed after they've already terminated, those operators wouldn't behave as expected.

@neilpa
Copy link
Member

neilpa commented May 5, 2015

I was thinking about pre-Interrupted world. However, this makes me wonder if an Interrupted event on the inner signals should be ignored rather than "poison" the outer signal in the same way as Error.

@neilpa
Copy link
Member

neilpa commented May 5, 2015

@jspahrsummers I opened #1967 to continue this discussion.

@jspahrsummers
Copy link
Member

#1966 was reverted because of bugs. Gonna reopen this so we can track it as an enhancement.

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

No branches or pull requests

7 participants