JensRavens/Interstellar

What's the right way to have a signal take no input

schwa opened this issue · 5 comments

schwa commented

This is my first approach:

let a = Signal()
a.flatMap() {
    () -> Int in
    return 42
}
a.next {
    print($0)
}
a.update()

Unfortunately next() gets fired twice.

Yes, that's intended behaviour so far. You're creating a new Signal of type Void that uses the convenience init. This init now stores the last result (a successful result of void) and every subscriber get's the last result on subscription. Then on update you run the whole chain again - resulting in the second next fired.

Currently I'm using a workaround of using a Signal<Bool>() and then update that with true (which also calls next on subscribe if it has been fired before). I see how handy a case of a void signal without storage would be for user interaction, but I'm still a bit hesitant to include a if $0 is Void everywhere in the source code of Signal. Also it would be a bit strange if a Signal of one type behaves differently to a signal of another type.

Maybe you have an idea for better semantics of void signals?

schwa commented

No I agree with you. I was just surprised at the behavior.

I wonder if an alternate form of init() might be possible. I'll play around and see what i can come up with.

Why does Signal send the last value on subscription? Could we have at least a choice to send only send values on update? I guess that's veering towards the hot & cold semantics...

Yep, it is. If you think about a UITextField having a textSignal: Signal<String>-property, most of the time it's handy to send the last value on subscribe to e.g. update a label. But this has several drawbacks: possible memory leaks, sending void on subscribe, breaking the first run of Thread-calls or just unexpected behaviour (like sending something when subscribing to a button). Therefore I'm not overly happy with the current implementation.

I have two ideas how to deal with this:

  • removing the value-property, so Signal becomes stateless (getting rid of the state also removes our last dependency on Foundation to sync the access on update)
  • adding an option to subscribe that defaults to false (this would correspond to key-value-observing's NSKeyValueObservingOptionInitial-option)

What do you think?

V2 now allows for Observable<Void>.