Skip to content
This repository was archived by the owner on Jan 26, 2022. It is now read-only.
This repository was archived by the owner on Jan 26, 2022. It is now read-only.

concatAll and concatMap rather than flatten and flatMap #60

Description

@benlesh

TL;DR: Try concatAll and concatMap because they're more specific to the actual behavior than flatten and flatMap, because "flat" has a more general meaning. Also, there's popular precedent in Rx

RxJS has a precedent here, as concatMap and concatAll do the same thing in RxJS as what is proposed here, where flatMap (which changed to mergeMap in v5 because it's too ambiguous as to how it's "flattening") does something very different and very specific to observing pushed values.

Specifically this is the behavior of concatMap and concatAll in RxJS:

concatMap: (roughly speaking) maps to a new observables, and plays them in a serial fashion, one at a time, end to end.

concatAll: Takes a higher-order Observable (Observable<Observable>), and queues up each inner observable, playing them in a serial fashion, one at a time, end to end.

/**
  * A test fixture that emits the passed values from a returned 
  * Observable one at a time, roughly one second apart, and completes
  * after emitting the last value.
  */
function ob(...args) {
  return new Observable(observer => {
    let i = 0;
    const id = setInterval(() => {
      observer.next(args[i++]);
      if (i >= args.length) observer.complete();
    }, 1000);
    return () => clearInterval(id);
  });
}


const source = ob(
  ob(1, 2),
  ob(3, 4),
  ob(5, 6),
);

const source2 = ob(1, 2, 3);

const mappingFn = n => ob(n, n + 1, n + 2);

const logger = { next(result) { console.log(result); } };
/* concatAll */
source.concatAll()
  .subscribe(logger);  // 1....2....3....4....5....6

/* concatMap */
source2.concatMap(mappingFn)
  .subscribe(logger); // 1....2....3....2....3....4....3....4....5

/* mergeAll (aka flatten elsewhere) */
source.mergeAll()
  .subscribe(logger); // 1.3.5....2.4.6   (roughly)

/* flatMap (now mergeMap in Rx 5) */
source2.mergeMap(mappingFn)
  .susbcribe(logger); // 1.2.3....2.3.4....3.4.5.

As you can see, concatMap is more like Array.prototype.flatMap (proposed) than RxJS's flatMap is. "flat" doesn't makes as much sense in Observable-land because there is more than two dimensions to deal choose to flatten, there's also time. With an array, there, could only be two dimensions, the length of the array, and the depth. Because of that ambiguity, RxJS opted to go with something more specific and moved away from flatMap and named it mergeMap (which as you can see above is very different from the flatMap proposed here).

It's just a proposal as an alternative to "smoosh".

I feel like I've rambled, but I hope that gets the idea across.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions