Observables support the ability to bind Observers to them. Observers receive an update when the contents of the cell change. Observerables are both Observables Observers.

Cells are Observerable, which means you can chain them to each other to publish and receive updates about changes in cell content.

Lets take a quick look:

RefCell<String> c1 = new RefCell<>("start");
RefCell<String> c2 = new RefCell<>("");
// c2 will now receive updates about changes to c1
// immediately after binding, c1 will update c2
c1.bind(c2);
// now c2 will contain "start"
c1.accept("end");
// now c2 will contain "end"

Two-way binds are also supported for Observerables (which cells are):

RefCell<String> c1 = new RefCell<>("start");
RefCell<String> c2 = new RefCell<>("");
// c2 will now receive updates about changes to c1
// and c1 will now receive updates about changes to c2
// c1 will bind c2 first
// so c1 will update c2 first
c1.bindBoth(c2);
// now c2 will contain "start"
c1.accept("end");
// now c2 will contain "end"
c2.accept("");
// now c1 will contain ""

Lets look at what Observers actually are:

RefCell<String> c1 = new RefCell<>("start");
c1.bind(incoming -> {
	System.out.println(incoming);
})
// "start" will be printed
c1.accept("end");
// now "end" will be printed

They’re just a functional interface, this means you can use them for whatever you’d like, not just binding cells together.

Bindings involving LateInitCells and derivatives are fine between each-other, but bindings between LateInitCells and RefCells of a non-nullable type get complex.

Knowing that Observers are just functional interfaces, lets solve the issues that arise when binding nullable to non-nullable cells.

RefCell<String> c1 = new RefCell<>("start");
LateInitCell<String> c2 = new LateInitCell<>();

c1.bind(c2);
// now c2 contains "start"

// this bind won't run if the arg is null
c2.bind(incoming -> {
	// don't update if the incoming data is null
	if (incoming == null) return;
	// update is like accept for observers
	c1.update(incoming);
});

c2.accept("end");
// now c1 contains "end"

c2.invalidate();
// now c2 contains null, while c1 still contains "end"

Observers can also be unbound:

RefCell<String> c1 = new RefCell<>("start");
RefCell<String> c2 = new RefCell<>("");
// c2 will now receive updates about changes to c1
// immediately after binding, c1 will update c2
c1.bind(c2);

// undoes that
// returns true if c2 was bound to c1
c1.unbind(c2);

c1.bindBoth(c2);

// unbindBoth also exists,
// unbinds both c2 from c1,
// and c1 from c2.
// returns true if either c2 was bound to c1, or c1 was bound to c2
c1.unbindBoth(c2);

Cool, that’s all for observability for now.