Browse Reactive Programming

Hot vs Cold Observables: Understanding the Difference in Rx

An in-depth exploration of Hot and Cold Observables in Reactive Extensions, their characteristics, differences, and practical examples using Clojure.

Introduction

Reactive Extensions (Rx) provide a powerful framework to work with asynchronous data streams. Observables are at the heart of Rx, acting as data emitters that can be processed using a variety of operators. However, observables can behave differently depending on whether they are “Hot” or “Cold”. Understanding these differences is crucial for designing efficient and effective reactive systems.

Hot vs Cold Observables

Cold Observables

  • Definition: A Cold Observable is one where data emission starts afresh and is independent for each observer that subscribes to it.
  • Characteristics:
    • Lazily evaluated: Only start emitting items when an observer subscribes.
    • Each observer receives the full data stream from the beginning, independent of when it subscribes.
    • Commonly used in scenarios like HTTP requests or database queries where each observer requires a fresh data set.

Hot Observables

  • Definition: A Hot Observable emits data regardless of whether there are subscribers or not. All observers share the same ongoing data stream.
  • Characteristics:
    • Actively producing data: Do not wait for observers to subscribe to start emitting.
    • Observers may miss some items if they subscribe late.
    • Useful in scenarios where data is continuously generated, such as mouse movements, sensor readings, or UI events.

Cold vs Hot Observable in Clojure

Cold Observable Example

Using manifold.stream to simulate a cold observable:

 1(require '[manifold.stream :as s])
 2
 3(defn cold-observable []
 4  (let [stream (s/stream)]
 5    (dotimes [i 5]
 6      (Thread/sleep 1000)
 7      (s/put! stream i))
 8    stream))
 9
10(let [stream (cold-observable)]
11  (s/consume println stream))

Explanation: In this example, a new stream is created for each call to cold-observable. Each subscriber receives the full sequence of numbers from 0 to 4, sequentially emitted.

Hot Observable Example

Using manifold/deferred to simulate a hot observable:

 1(require '[manifold.stream :as s])
 2
 3(def stream (s/stream))
 4
 5(defn hot-observable []
 6  (dotimes [i 5]
 7    (Thread/sleep 1000)
 8    (s/put! stream i)))
 9
10(future (hot-observable))
11(s/consume println stream)

Explanation: In the hot observable example, the hot-observable function continuously emits data to a shared stream. Subscribers may join in at any point and only see future emissions.

UML Sequence Diagram

    sequenceDiagram
	    participant C as Cold Observable
	    participant H as Hot Observable
	    participant O1 as Observer 1
	    participant O2 as Observer 2
	
	    Note over C,H: Observable not started
	    rect rgb(220, 220, 255)
	        O1->>+C: Subscribe
	        C->>O1: Emit data sequence
	    end
	    
	    rect rgb(255, 220, 220)
	        H->>+H: Start emitting data
	        Note right of H: Active before subscribers
	        O2->>+H: Subscribe
	        H->>O2: Emit missed sequence\nstart receiving data
	    end

Explanation: This sequence diagram shows how Cold and Hot Observables operate. In the Cold Observable, data generation only begins on subscription. In contrast, the Hot Observable continuously emits data even before any subscription.

  • Observer Pattern: Both Hot and Cold observables embody the Observer Pattern as they notify subscribers (observers) about new data changes.
  • Publish-Subscribe Pattern: Hot observables often resemble the Publish-Subscribe pattern where multiple subscribers receive data from a common source.

Additional Resources

  • ReactiveX Documentation: Comprehensive documentation on Rx concepts and operators.
  • Clojure’s Manifold Library: Manifold provides a great set of tools for managing asynchronous programming and streams in Clojure.
  • “Reactive Programming with RxJava”: A book covering the fundamentals and advanced features of RxJava, applicable concepts are transferable to Clojure.

Summary

Understanding Hot and Cold Observables is critical in reactive programming, especially in systems that demand high concurrency and real-time data processing. Cold Observables provide independent data streams for each observer, ensuring fresh data sets, while Hot Observables share a common data stream, suitable for real-time and live data scenarios. With the practical examples in Clojure and their implementation nuances explained, this article provides a foundation for effectively using Rx patterns in modern applications.