xstream icon indicating copy to clipboard operation
xstream copied to clipboard

introduce lazy stream as alternative to proxy

Open samdesota opened this issue 7 years ago • 3 comments

The current proxy design using .imitate is kinda a unusual api in world where almost all other stream creation operators are pure, and typescript can't automatically infer its type since it must be created before the result is available

What if instead, you used:

var first$ = xs.lazy(() => second$).map(x => x * 10).take(3);
var second$ = first$.map(x => x + 1).startWith(1).compose(delay(100));

Now, the type can be inferred with typescript and you don't need the extra lines for .imitate(). This works by creating a producer which stores the () => second$ function, then once .subscribe is called (after second$ has been assigned), () => second$ is called its result is observed

samdesota avatar Jan 13 '18 15:01 samdesota

Nice idea, you could probably release this as a separate package. I think in xstream we will gradually take distance from the imitate API, which for Cycle.js purposes is starting to look less necessary.

staltz avatar Jan 29 '18 14:01 staltz

@mrapogee any news on your proposal? Would be great to have an implementation of It.

If I understand well it's a combination of of/map/flatten

import xs from 'xstream'

const first$ = xs
    .of(() => second$)
    .map(f => f())
    .flatten()
    .map(x => x * 10)

const second$ = first$.map(x => x + 1).startWith(1)

second$.addListener({
    next: i => console.log(i),
    error: err => console.error(err),
    complete: () => console.log('completed')
})

ftaiolivista avatar Oct 14 '19 08:10 ftaiolivista

It's funny, I just started using xstream again this week. Ended up re-implementing lazy privately again via:

import xs from "xstream";

const lazy = getStream => {
  return xs.create({
    start(sink) {
      this.sub = getStream().subscribe(sink);
    },

    stop() {
      if (this.sub) {
        this.sub.unsubscribe();
        this.sub = null;
      }
    }
  });
};

Though given that xsteam is multicast, it might make more sense to do something like:

import xs from "xstream";

const empty = Symbol('empty')
const lazy = getStream => {
  return xs.create({
    stream: empty,

    start(sink) {
      if (this.stream === empty) {
        this.stream = getStream()
     }

      this.sub = this.stream.subscribe(sink);
    },

    stop() {
      if (this.sub) {
        this.sub.unsubscribe();
        this.sub = null;
      }
    }
  });
};

Maybe I'll get around to publishing it some time this week.

samdesota avatar Oct 14 '19 16:10 samdesota