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

Replace ColdSignal and HotSignal with SignalProducer and Signal #1655

Merged
merged 67 commits into from Jan 18, 2015

Conversation

jspahrsummers
Copy link
Member

After the long discussion in #1650, I invited @NachoSoto, @andymatuschak, and @kastiglione to talk more in-depth about the Swift APIs, and specifically where they need improvement.

We had a really, really great brainstorming session, and this is the result. The good news is that we all feel pretty good about this direction, and the bad news is that everything is getting rewritten again. :trollface:

The important bits are documented on the types themselves, but here’s the handy Quick Start guide of the proposed changes:

  1. HotSignal<T> will be replaced by Signal<T>. Besides the name change, these signals can now send Error and Completed events. This avoids a lot of the lifecycle weirdness that has come up with a value-only HotSignal.
  2. ColdSignal<T> will be replaced by SignalProducer<T>. As the name implies, a signal producer creates Signals (via the start method). You can kind of think of the relationship as something like:
    • SignalProducer : Signal :: RACSignal : subscription
    • SignalProducer : Signal :: class : instance
  3. Most of the basic operators are written in terms of Signal, but can be lifted to apply to SignalProducer instead.
  4. Operators that benefit from “cold” semantics, like retry and repeat, are written in terms of SignalProducer.

The advantages here are:

  • The relationship between “hot” and “cold” signals is now much more explicit and well-defined. A “cold” signal (a producer) creates “hot” signals, each of which represents a “subscription” (in RAC 2.x terms).
  • Many operators only have to be written once, in terms of Signal, and can be lifted to the SignalProducer level.
  • The semantics and/or difficulties of converting between “hot” and “cold” are more obvious, I think. You don’t need to swap between them on the fly, because they mean different things.
  • Signal lifetime is now consistent, and completely defined by the event stream. Signal producers don’t do anything special—they really are just value types, and don’t encode any information about lifetime.

I’ll also make some notes in the changes below, to explain more specific things. Please leave feedback if you have it! 🙇

@jspahrsummers jspahrsummers added this to the 3.0 milestone Dec 28, 2014
/// A mutable property of type T that allows observation of its changes.
///
/// Instances of this class are thread-safe.
public final class Property<T> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is purely a convenience type for binding. It can be implemented entirely in terms of the SignalTemplate.buffer constructor.

@jspahrsummers
Copy link
Member Author

@jspahrsummers jspahrsummers changed the title [RFC] Replace ColdSignal and HotSignal with SignalTemplate and Signal (a.k.a. Round and Around We Go) [RFC] Replace ColdSignal and HotSignal with SignalTemplate and Signal Dec 28, 2014
@jacksonh
Copy link

How about SignalGenerator, or SignalBuilder instead of SignalTemplate?

giphy

@jspahrsummers
Copy link
Member Author

SignalGenerator

@jacksonh GeneratorType already exists in the standard library as a mutable thing that you “exhaust.”

SignalBuilder

@andymatuschak pointed out that the Builder pattern refers to something very specific, and this would not be that.

@robb
Copy link
Member

robb commented Dec 28, 2014

I kinda like Task as you mentioned before, as in let task = Template.start() (if I understood you correctly that is)

There are also no RAC 2.0 preconceptions around these names, which could people migrating.

@jspahrsummers
Copy link
Member Author

Task is a bit misleading for the “hot” thing, because IMO it implies something that might have methods like cancel() and start(). When you get a Signal, all you can do is observe it—I think the name is fitting.

public func combinePrevious<T>(initial: T)(signal: Signal<T>) -> Signal<(T, T)>
public func concat<T>(next: Signal<T>)(signal: Signal<T>) -> Signal<T>
public func delay<T>(interval: NSTimeInterval, onScheduler scheduler: DateScheduler)(signal: Signal<T>) -> Signal<T>
public func dematerialize<T>(signal: Signal<Event<T>>) -> Signal<T>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 no more identity!

@jacksonh
Copy link

I do think there is a much better name out there than Signal and SignalTemplate. Especially if one of the original stated problems was I wonder if it is doing more harm than good to make ColdSignal and HotSignal sound like almost the same thing.

giphy-1

///
/// After an `Error` or `Completed` event has been added to the buffer, the
/// sink will not add any further events.
public static func buffer(capacity: Int) -> (SignalTemplate, SinkOf<Event<T>>)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. Nice docstring too.

@NachoSoto
Copy link
Member

I love it! I agree there's probably a better name than SignalTemplate, but except for that I'm really happy with where this is going.

@kastiglione
Copy link
Member

@jacksonh Another aspect to the name is whether it's natural to be the subject of map, filter, etc. These operators seem to be slightly more fitting of a SignalTemplate than a SignalGenerator or SignalBuilder.

@kastiglione
Copy link
Member

For some context on the name SignalTemplate. As mentioned above, a number of names were suggested but each with some argument against it. Nearer to the end of the discussion, words like "Blueprint", "Formula", and similar were suggested, at which point I started thinking aloud about how @Coneko pointed out that in RAC 2, a signal network gets assembled as one step, and then once it is subscribed to, many of those signal objects can be discarded because it's the subscription network through which the data flows. I mentioned how I see the signal setup as almost a compilation step, and the data flow the runtime. From that @andymatuschak suggested template, which I presumed was in reference to C++ templates, so it made a lot of sense for me.

A better name would be ideal, but this name seemed to meet criteria that the other names didn't, so it has that going for it.

@jspahrsummers
Copy link
Member Author

A few other name ideas (to replace SignalTemplate):

  • SignalModel
  • SignalPrototype, PrototypeSignal
  • SignalDesign

Out of those, I kinda like “prototype” more than “template.”

@Tiger6688
Copy link

oh my lady gaga,How about SignalT??

@kastiglione
Copy link
Member

Prototype has less domain baggage, but also seems less literally correct. I'm 👍 to either.

@andymatuschak
Copy link
Contributor

Out of those, I kinda like “prototype” more than “template.”

In prototype-based languages, a "prototype of an X" is itself usable as an "X." That is to say: one could reasonably expect a SignalPrototype to be usable as a Signal. It wouldn't be reasonable to expect a "signal template" to be usable as a signal, though.

/// Signals started by the returned producer will not send a value until both
/// inputs have sent at least one value each.
public func combineLatestWith<T, U>(otherSignalProducer: SignalProducer<U>)(producer: SignalProducer<T>) -> SignalProducer<(T, U)> {
return producer.lift(combineLatestWith)(otherSignalProducer)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How freaking awesome is this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jspahrsummers jspahrsummers mentioned this pull request Jan 18, 2015
@jspahrsummers jspahrsummers changed the title [RFC] Replace ColdSignal and HotSignal with SignalProducer and Signal Replace ColdSignal and HotSignal with SignalProducer and Signal Jan 18, 2015
@jspahrsummers
Copy link
Member Author

Trying to implement everything here was a mistake, since we're basically talking about the whole framework. So, instead, I've annotated outstanding TODOs and would like to merge this as-is (and create smaller PRs into swift-development after that).

🙌

@jspahrsummers
Copy link
Member Author

Gonna #yolo this so I can create dependencies that don't have crazy diffs. :trollface:

jspahrsummers added a commit that referenced this pull request Jan 18, 2015
Replace ColdSignal and HotSignal with SignalProducer and Signal
@jspahrsummers jspahrsummers merged commit 12dca98 into swift-development Jan 18, 2015
@jspahrsummers jspahrsummers deleted the signal-templates branch January 18, 2015 08:49
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

Successfully merging this pull request may close these issues.

None yet