Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
The Great Swiftening (a.k.a. the new 3.0) #1382
To get us started, I basically just subtree merged jspahrsummers/RxSwift into here, then bridged several RAC classes back and forth.
referenced this pull request
Jun 19, 2014
referenced this pull request
Jun 20, 2014
You can intuitively think of an
Here's the best part: all of this stuff is bridged to RAC 2.x concepts, so you should be able to try this out in a Swift project today (though the usual disclaimers apply about not being production-ready, and me possibly breaking everything in the future).
Let me know what you think.
I've been trying to hold my tongue on the issue of naming conventions in RAC + RxSwift for over year now. I figured Objective-C is different enough to possibly need its own naming, simply because of namespacing, or protocal/implementation conflicts while adhering to a Apple coding guidelines. Basically, I have no idea.
That being said, RxSwift doesn't fall prey to namespacing issues, and it's a new language, so interface/protocol naming conventions could (maybe not should, though) be overridden without too much of a pounding from our Apple overlords.
It should also be said that, while I have plenty of experience with Rx in general, I have very little experience with RAC, Objective-C, or Swift (although I hope to become more familiar with Swift sooner rather than later).
My main concern on this is with the matter consistency. My second concern is with general accuracy. By second hand experience, I would suspect the order of these concerns are reversed in your case, and I believe this reversal is a product of a shared goal: to let developers think quickly about Rx.
That being said, I disagree with many of the RAC naming conventions.
Observable, for instance, is a clearly defined pattern by which a consumer can indicate to a producer that it would like to receive that which the producer produces. The nature of this subscription process has traditionally been, for the most part, side-effect free. I'd like to believe that Rx started this way, but eventually realized the true potential of the pattern: Dynamically Generated Asynchronous Functions with Multiple Return Values.
Perhaps the name of Observable should have been changed to DynamicAsyncMultiRetFunc, or Functoree, or something equally nondescript. Never-the-less, the name was not changed, and many a years has the name been Observable. That is, except within the confines of RAC.
Unless explicitly mentioned, one would have a difficult time determining that RAC were based on Rx, or even inspired by, for that matter. Furthermore, it would be more difficult to come from a world of Rx and attempt to work in the world of RAC. The brain can only hold so much information, and if one wishes to work in both of these worlds, it requires twice as much memory consumption. Or at least, twice as many hash keys (or whatever it is we use for lookups in that big grey thing we think with).
Therefore, by potentially reducing the barrier of entry to RAC from the outside world via a proprietary and potentially more accurate naming convention, the solution itself has definitely increased the barrier of entry to RAC from the Rx world. From which, it could be, many RAC users emerge. The exclusivity works both ways, however. The barrier from Rx to RAC is the same as the barrier from RAC to Rx, by which new RAC users are discouraged from using Rx learning materials, as they do not map one-to-one with the RAC naming conventions. Worse, some of the conventions are contrary.
If any custom naming conventions are definitively or majorly clearer than the historical Rx naming conventions, then the difference is not simply justified, but demanded. Not only for RAC, but for Rx in general. However, if this is not the case, I argue that the difference between the two can only serve to compound the confusion and increase the cognitive overhead working with Rx. A few days of waking up on the opposite side of the bed tends to cause the new side to feel natural.
My concrete concerns with this particular pull request are as follows:
Yeah, naming these the same as established Rx names but having fundamentally different semantics is a pretty big troll for people coming from Google Searches. At least use "Sequence" and "Signal" so they don't conflict
@cwharris Thanks for writing up your thoughts and posting them here! I'll respond to each of your points in turn:
We've historically pursued these goals for naming (in roughly this order):
I would venture to say that most RAC users do not have familiarity with Rx, and do not particularly care whether their skills transfer between the two, so a lower barrier-to-entry for the typical Cocoa programmer has always been more important to us.
The Observer pattern is very familiar to most developers, and this is precisely the problem. They are familiar with “observation” as something that does not cause side effects.
I strongly dislike overloading the term for a stream that causes stuff to happen on observation (and it's not even predictable, given the existence of hot and "warm" observables, which use the same naming).
As mentioned above, this is one of the least important goals for us. We do care about it, but we care about other stuff—like The Right Way™ to do things—way more. If we think that we can do something better than Rx, we will (however small or large the change).
This is definitely a huge problem, because fake familiarity is more confusing than the unfamiliar.
I would love to change the names used here, but I haven't yet come up with anything better. It should definitely happen before this is sanctioned as production-ready, though.
The latter. This is why
I would greatly prefer a name that clearly conveys its meaning to reader, without any need to look up documentation.
"Hot" and "cold" are the most confusing concepts in Rx and RAC right now, so I don't think it's helpful to make reference to them. This is exactly the problem I'm trying to solve—codifying the distinction in a more helpful way that's less prone to misunderstandings and misuse.
@paulcbetts As mentioned above,
I'm also not a big fan of
Sorry, missed this one about
@cwharris The current implementation of
In other words, the closure passed to the constructor is executed immediately, and only once, making it mostly impossible to implement “cold” behaviors.
That's exactly my point. What if you have a lack of experienced RAC users because the transition from Rx imparts a large cognitive overhead? That, and Objective-C was the main barrier to entry into the RAC world. Now that Swift exists, there's the potential for a lot more cross-over.
I actually edited my answer after you quoted some of it. I also suggest
Picard can portray my feelings more accurately than I, in this instance.
I don't think “behavior” is very clear to anyone without FRP or Rx experience. I may revert to “signal” (which, incidentally, behaviors have been referred to as) because it's the least-bad option I can see.
Still not sure what to do for the cold stream of events.
added a commit
this pull request
Jul 3, 2014
I do not come from Rx, and I can confirm that Signal is often a synonym for Behavior, which represents a value at all points in time. Events usually represent something which has a value only at discrete moments.
Most systems implement Signals as discretely changing, but still the Signal represents a value at all moments in time, even between the updates.
Some systems also let you map over the updates of a Signal's value as if it were an Event, but it is still not an Event.
Bacon.js uses the terms EventStream and Property for its hot signals. It
On Thursday, July 3, 2014, jlawton firstname.lastname@example.org wrote:
I understand "signal" as @jspahrsummers: something that is either a behaviour or an event stream.
I think it's often regarded as a synonym for one or the other because the difference between the two is not widely understood.
A behaviour is a value that changes over time: a value is defined at all times after the behaviour "starts existing".
An event stream is a collection of events over time. Events can occur at any time after the stream has been created, including never.
The two concepts are very different, but they are connected: any behaviour can be converted in an event stream by considering changes in value as events, and any event stream can be converted in a behaviour by calculating a value based on the events that have happened so far.
Because the most common use cases for both have to do with discrete time rather than continuous time the conversion between the two is very natural, which confuses the two.
In RAC3 behaviours are represented by ObjC properties, event streams are represented as signals. Note that it does not provide any way of working with behaviours directly, only ways to convert them to and from event streams.
Note that all of this still doesn't make any distinction between hot and cold or pull and push.
Looks good so far, but I have a big change to request: just like
This would help keeping the interactions between the parts of the RAC system within RAC's internals, allowing us to change the internal assumptions about the system without touching the external semantics.
For example, with
@Coneko FWIW, my goal is that this type should always be cold (in the sense of, “different observers may see a different version or timing of events”) or warm. At the very least, we shouldn't include any features that make it possible to use differently.
I could see an argument for making