New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cycle Diversity: generalize for any stream library #196

Closed
staltz opened this Issue Jan 9, 2016 · 74 comments

Comments

@staltz
Member

staltz commented Jan 9, 2016

@TylorS and I started discussing how to migrate to RxJS 5, and/or support most.js streams without the need for a fork (Motorcycle.js) which mostly has copy-pasted code from some Cycle.js libraries.

We arrived at a proposal: Build a "base" run() function which is generic and assumes no stream library. It uses "stream adapters" to agree on an interface for each stream library. We need to build an adapter for each stream library. We also need to build "rx run()", "most run()" which basically utilizes the common "base run()" but specify which stream library adapter is used. Drivers are given the stream adapter object from run(), and can written using whatever stream library.

@cycle/rx-run

import baseRun from '@cycle/base'
import streamAdapter from '@cycle/rx-adapter'

const Cycle = {
  run: (main, drivers) => baseRun(main, drivers, {streamAdapter})
}

export default Cycle

@cycle/dom

function domDriver(sink$) {...}

domDriver.streamAdapter = rxAdapter // mostAdapter 

Tasks to do

  • Create @cycle/base repo (essentially this PR #198 there) https://github.com/cyclejs/base
  • Write test for @cycle/base ensuring one-liner drivers work properly with default adapter.
  • Build https://github.com/cyclejs/rx5-adapter with tests, using StreamAdapter interface from base
  • Build https://github.com/cyclejs/rx4-adapter with tests, using StreamAdapter interface from base
  • PR on Cycle Core to implement it as @cycle/base + @cycle/rx-adapter, with #200 in mind
  • Make canary version for core
  • Make @cycle/rx-run npm package alias for @cycle/core
  • Rewrite Cycle DOM Driver in TypeScript with transposition off by default
  • Update base to export CycleSetup interface
  • Fix Cycle DOM diversity to adapt the out-facing streams for the app's stream library
  • Convert some cycle-examples to use the canary version of dom with RxJS 5
  • Cycle HTTP driver in TypeScript and using driverFn.streamAdapter = rxAdapter
  • Make canary versions for http, test it around
  • Update power-ui to Diversity
  • xstream-adapter
  • xstream-run
  • Fix Cycle DOM last bugs with DOMSource.events() and isolate
  • Soft release core, dom, *-run, http, jsonp RC versions
  • Build https://github.com/cyclejs/most-adapter in JS with tests, using StreamAdapter interface from base
  • create @cycle/most-run https://github.com/cyclejs/most-run with #200 in mind
  • Unnecessary: Update motorcycle drivers to use driverFn.streamAdapter = mostAdapter
  • Update examples and TodoMVC to Diversity & xstream
  • Make bmi-typescript example, and fix Cycle DOM TypeScript problems, issue #307
  • Write http-random-user in TypeScript to make sure HTTP Driver is also working well
  • Change HoldSubject to Subject in stream adapters. It's not needed.
  • Rework makeHTMLDriver(callback)
  • mockDOMSource should return a stream of the app's own stream library.
  • DOMSource.select().elements should return WhateverStream interface, not type any
  • foo-adapter and foo-run: remove dispose(), add remember()
  • Update cycle history to use stream adapter remember()
  • Update TodoMVC using cycle history
  • Fix Cycle DOM documentation generation
  • Update cycle.js.org
  • cycle.js.org documentation page
  • Write Release notes and migration guide
  • Merge branches diversity to master, and publish non-rc versions
    • Cycle Core / Rx Run
    • DOM
    • HTTP
    • JSONP
    • examples
    • cyclejs.github.io
    • others
  • npm deprecate @cycle/core, use rx-run
  • Cycle DOM rxjs-typings, rx-typings, most-typings
  • Cycle HTTP rxjs-typings, rx-typings, most-typings

Breaking changes so far

  • DOMSource.select().observable => DOMSource.select().elements()
  • new Cycle.run API for those cases where sources and sinks are wanted: #200
  • Snabbdom instead of virtual-dom
    • breaking changes with hyperscript way of using attrs
  • top-level <svg> element is created with hyperscript-helpers but children elements created with hyperscript
  • mockDOMSource(sa, config) now takes a Stream Adapter as the first argument
  • makeHTMLDriver() => makeHTMLDriver(effectFn, options)
  • No more onError callback as an option to makeDOMDriver()
  • No more sinks.dispose and sources.dispose
  • HTML Driver returns and HTMLSource mimicking DOMSource. HTMLSource.element$ is the stream of HTML strings
  • HTTP Source is not response$$ but contains it. It's an object with select(category: string): Observable<Observable<Response>>, filter(predicate: (res$: ResponseStream) => boolean): HTTPSource and response$$ property.

@staltz staltz added the feature label Jan 9, 2016

@erykpiast

This comment has been minimized.

Show comment
Hide comment
@erykpiast

erykpiast Jan 9, 2016

Contributor

I'm not sure if I understand correctly, so please tell me, which statement is the closest to your idea.

  1. you wish to allow people to create Cycle drivers with whatever library they want, not only Rx, and make Cycle-core transparent (library agnostic), so if all the drivers are written with, ex., most.js, application may be written using most too and there is no dependency on Rx?
  2. or you propose to make inside Cycle kind of translation from any-streams-library.js to other-stream-library.js, to allow different drivers be written with different libraries and application in any other supported library?
Contributor

erykpiast commented Jan 9, 2016

I'm not sure if I understand correctly, so please tell me, which statement is the closest to your idea.

  1. you wish to allow people to create Cycle drivers with whatever library they want, not only Rx, and make Cycle-core transparent (library agnostic), so if all the drivers are written with, ex., most.js, application may be written using most too and there is no dependency on Rx?
  2. or you propose to make inside Cycle kind of translation from any-streams-library.js to other-stream-library.js, to allow different drivers be written with different libraries and application in any other supported library?
@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

I have already begun experimenting with this here at https://github.com/TylorS/cycle-core/tree/rxjs-most-interoperability. It requires no breaking changes to the current cycle-* drivers. Most.js drivers are supported using (this is not a agreed upon or final API)

function driverFn() {}
driverFn.type = 'most'

There are some issues still that need to be resolved. Cycle-DOM for example has 2 failing tests, but I haven't had the time just yet to investigate the issues.

I'm also interested in simply creating a set of streamLibrary -> streamLibrary conversion functions to experiment with drivers being in control of where to convert from one library to another.

Member

TylorS commented Jan 9, 2016

I have already begun experimenting with this here at https://github.com/TylorS/cycle-core/tree/rxjs-most-interoperability. It requires no breaking changes to the current cycle-* drivers. Most.js drivers are supported using (this is not a agreed upon or final API)

function driverFn() {}
driverFn.type = 'most'

There are some issues still that need to be resolved. Cycle-DOM for example has 2 failing tests, but I haven't had the time just yet to investigate the issues.

I'm also interested in simply creating a set of streamLibrary -> streamLibrary conversion functions to experiment with drivers being in control of where to convert from one library to another.

@erykpiast

This comment has been minimized.

Show comment
Hide comment
@erykpiast

erykpiast Jan 9, 2016

Contributor

"streamLibrary -> streamLibrary" approach would make Cycle's interoperability and interchangeability outstanding! Especially if it's done inside core (or somewhere else, but to make it transparent to the framework user and driver creator).

Contributor

erykpiast commented Jan 9, 2016

"streamLibrary -> streamLibrary" approach would make Cycle's interoperability and interchangeability outstanding! Especially if it's done inside core (or somewhere else, but to make it transparent to the framework user and driver creator).

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

@erykpiast The purpose of this issue/initiative is to:

  • Allow main() to be written in any of these stream libraries: RxJS 4, RxJS 5, most, Bacon.js, Kefir.
  • Allow using most-based drivers, such as Motorcycle's outstanding most + snabbdom driver.
  • Keep the simple API for drivers: just functions that input and/or output streams. In particular, it's important to allow people to create one-liner drivers without a lot of boilerplate. We need a solution that assumes drivers, unless specified, are using the same stream library used by run() when specified in options.streamLibrary in Cycle.run(main, drivers, options).
Member

staltz commented Jan 9, 2016

@erykpiast The purpose of this issue/initiative is to:

  • Allow main() to be written in any of these stream libraries: RxJS 4, RxJS 5, most, Bacon.js, Kefir.
  • Allow using most-based drivers, such as Motorcycle's outstanding most + snabbdom driver.
  • Keep the simple API for drivers: just functions that input and/or output streams. In particular, it's important to allow people to create one-liner drivers without a lot of boilerplate. We need a solution that assumes drivers, unless specified, are using the same stream library used by run() when specified in options.streamLibrary in Cycle.run(main, drivers, options).
@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

I'm working on an external library to convert between different stream implementations. I believe it will likely be required for a driver to supply a place to be able to convert it's streams when there are more complex streams such as the DOM Driver.

Member

TylorS commented Jan 9, 2016

I'm working on an external library to convert between different stream implementations. I believe it will likely be required for a driver to supply a place to be able to convert it's streams when there are more complex streams such as the DOM Driver.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

Great 👍
Modularity for the win

Member

staltz commented Jan 9, 2016

Great 👍
Modularity for the win

@erykpiast

This comment has been minimized.

Show comment
Hide comment
@erykpiast

erykpiast Jan 9, 2016

Contributor

What about interoperability of nested cycles? There is plan to make possible connections between cycle applications built with different libraries? To be honest I don't really believe people would like to use many stream libraries in production-ready applications (at the end of the day size matters), but if we make it possible for drivers, it will be consistent to provide the same abilities to nested cycles.

@TylorS do you think this conversion utility should be used in drivers internally? I see another possible approach: for drivers like Cycle-DOM, thin compatibility layers may be built, one for each library. If driver creator defines some interface to build ex. multi-level streams, implementation (from separated package like cycle-dom-kefir) may be passed to the driver.

import { run } from '@cycle/core';
import makeDomDriver from '@cycle/dom';
import kefirAdapter from '@cycle/dom-kefir-adapter';

Cycle.run(main, {
  DOM: makeDomDriver('#app-container', kefirAdapter)
});

The adapter will implement functions like createEventsStream etc. in Kefir, using stream conversion library internally. Driver itself will stay small and library agnostic, hovewer its configuration will become more complicated.

Just an idea.

Contributor

erykpiast commented Jan 9, 2016

What about interoperability of nested cycles? There is plan to make possible connections between cycle applications built with different libraries? To be honest I don't really believe people would like to use many stream libraries in production-ready applications (at the end of the day size matters), but if we make it possible for drivers, it will be consistent to provide the same abilities to nested cycles.

@TylorS do you think this conversion utility should be used in drivers internally? I see another possible approach: for drivers like Cycle-DOM, thin compatibility layers may be built, one for each library. If driver creator defines some interface to build ex. multi-level streams, implementation (from separated package like cycle-dom-kefir) may be passed to the driver.

import { run } from '@cycle/core';
import makeDomDriver from '@cycle/dom';
import kefirAdapter from '@cycle/dom-kefir-adapter';

Cycle.run(main, {
  DOM: makeDomDriver('#app-container', kefirAdapter)
});

The adapter will implement functions like createEventsStream etc. in Kefir, using stream conversion library internally. Driver itself will stay small and library agnostic, hovewer its configuration will become more complicated.

Just an idea.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

We can always endlessly abstract everything away, but I don't think that's the purpose. It's enough if we allow people to build main() in their preferred stream library. For nested components (if I understood that's what you meant by "nested cycles") I think a better idea will be a utility library to convert a Cycle main() to a Web Component (or a Web standard custom element).

Member

staltz commented Jan 9, 2016

We can always endlessly abstract everything away, but I don't think that's the purpose. It's enough if we allow people to build main() in their preferred stream library. For nested components (if I understood that's what you meant by "nested cycles") I think a better idea will be a utility library to convert a Cycle main() to a Web Component (or a Web standard custom element).

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

@erykpiast Your approach is bascially what I have in mind, but converting from one to another is actually pretty easy and general so it would probably be handled as an option to run(). This is just an idea too.

function driverFn(sink$, conversionFn) {
  return conversionFn(sink$.map(x => x * x))
}

driverFn.streamLibrary = 'rx' // Tells run that it's written in rx

run(main, {other: driverFn}, {streamLibrary: 'rx'}) // means write your main() with Rx
run(main, {other: driverFn}, {streamLibrary: 'most'}) // write your main() with most

So anywhere that a stream is produced and returned back to main, conversionFn() would just have to be called to convert the stream from x -> y.

Member

TylorS commented Jan 9, 2016

@erykpiast Your approach is bascially what I have in mind, but converting from one to another is actually pretty easy and general so it would probably be handled as an option to run(). This is just an idea too.

function driverFn(sink$, conversionFn) {
  return conversionFn(sink$.map(x => x * x))
}

driverFn.streamLibrary = 'rx' // Tells run that it's written in rx

run(main, {other: driverFn}, {streamLibrary: 'rx'}) // means write your main() with Rx
run(main, {other: driverFn}, {streamLibrary: 'most'}) // write your main() with most

So anywhere that a stream is produced and returned back to main, conversionFn() would just have to be called to convert the stream from x -> y.

@HighOnDrive

This comment has been minimized.

Show comment
Hide comment
@HighOnDrive

HighOnDrive Jan 9, 2016

Very exciting, Cycle as a "Web Component (or a Web standard custom element)" sounds great too. Embedding anywhere everywhere sounds like a famous-ly awesome idea!

HighOnDrive commented Jan 9, 2016

Very exciting, Cycle as a "Web Component (or a Web standard custom element)" sounds great too. Embedding anywhere everywhere sounds like a famous-ly awesome idea!

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

Here is the start of this stream conversion library
https://github.com/TylorS/stream-conversions

Member

TylorS commented Jan 9, 2016

Here is the start of this stream conversion library
https://github.com/TylorS/stream-conversions

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

👍 I like the API!

Member

staltz commented Jan 9, 2016

👍 I like the API!

@Cmdv

This comment has been minimized.

Show comment
Hide comment
@Cmdv

Cmdv Jan 9, 2016

Contributor

I like the idea giving devs the option to chose stream library of preference.
But I worry a little with giving people support. Most & Rx are quite similar and all the examples on Docs assume Rx but how do we support people using Bacon.js?
Just wonder if it will add a level of confusion as to what the right way to do things would be.
Superb for people with previous Cycle experience but a little daunting for new comers?
Just a devils advocate thought process but I always like to think of new comers :)

Contributor

Cmdv commented Jan 9, 2016

I like the idea giving devs the option to chose stream library of preference.
But I worry a little with giving people support. Most & Rx are quite similar and all the examples on Docs assume Rx but how do we support people using Bacon.js?
Just wonder if it will add a level of confusion as to what the right way to do things would be.
Superb for people with previous Cycle experience but a little daunting for new comers?
Just a devils advocate thought process but I always like to think of new comers :)

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

Good concerns @Cmdv. The point here is to give choice. That's different from forcing people to choose. I'll still advocate in cycle.js.org docs one stream library (most likely RxJS 5), but I'm happy to support people who want (or need) to use most or Bacon.js or anything else. For people who know what they need, I want to make it easy. For people who don't know what they need, I also want to make it easy.

I'm still planning to write that "Real world apps" chapter for cycle.js.org, where there will be a suggested stack of tools.

Member

staltz commented Jan 9, 2016

Good concerns @Cmdv. The point here is to give choice. That's different from forcing people to choose. I'll still advocate in cycle.js.org docs one stream library (most likely RxJS 5), but I'm happy to support people who want (or need) to use most or Bacon.js or anything else. For people who know what they need, I want to make it easy. For people who don't know what they need, I also want to make it easy.

I'm still planning to write that "Real world apps" chapter for cycle.js.org, where there will be a suggested stack of tools.

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

@staltz This API for which? stream-conversions or above that for drivers?

@Cmdv I don't know anything about Bacon.js or any of the other libraries, but I think we're just getting started with just Rx and Most. Basically the idea is to have an approach to allow Cycle.js to be a general implementation of a pattern, ultimately paving the way for when we can just use ES standard Observables and the interoperability that will bring.

Member

TylorS commented Jan 9, 2016

@staltz This API for which? stream-conversions or above that for drivers?

@Cmdv I don't know anything about Bacon.js or any of the other libraries, but I think we're just getting started with just Rx and Most. Basically the idea is to have an approach to allow Cycle.js to be a general implementation of a pattern, ultimately paving the way for when we can just use ES standard Observables and the interoperability that will bring.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

stream-conversions

Member

staltz commented Jan 9, 2016

stream-conversions

@Cmdv

This comment has been minimized.

Show comment
Hide comment
@Cmdv

Cmdv Jan 9, 2016

Contributor

@staltz @TylorS lovely I just wanted to make sure there was an advocated way and more experienced Devs could chose the stream library of choice.

Didn't want to add lots of confusion to the table, because Cycle and FRP isn't the easiest thing to get your head around if you've never used streaming libraries. So clarity and less abstraction is needed for those new devs. This can be just at a Documentation level or advocated level but wanted to make sure new dev's weren't coming to cycle thinking:

What are these stream libraries which one do I use? I just want to have a little play and already I have to make important choices about the core of what I'm building.

Then ultimately scaring them off :)

Contributor

Cmdv commented Jan 9, 2016

@staltz @TylorS lovely I just wanted to make sure there was an advocated way and more experienced Devs could chose the stream library of choice.

Didn't want to add lots of confusion to the table, because Cycle and FRP isn't the easiest thing to get your head around if you've never used streaming libraries. So clarity and less abstraction is needed for those new devs. This can be just at a Documentation level or advocated level but wanted to make sure new dev's weren't coming to cycle thinking:

What are these stream libraries which one do I use? I just want to have a little play and already I have to make important choices about the core of what I'm building.

Then ultimately scaring them off :)

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

@Cmdv The default for the foreseeable future at least will be rx 4 and rx 5 when that's ready. I don't think there is any current plan or need for breaking changes application side. This should all be handled in run() and inside of the drivers transparently.

Member

TylorS commented Jan 9, 2016

@Cmdv The default for the foreseeable future at least will be rx 4 and rx 5 when that's ready. I don't think there is any current plan or need for breaking changes application side. This should all be handled in run() and inside of the drivers transparently.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 9, 2016

Member

Actually one of the biggest things is being able to use most.js in a DOM Driver. In principle it should have better performance.

Member

staltz commented Jan 9, 2016

Actually one of the biggest things is being able to use most.js in a DOM Driver. In principle it should have better performance.

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

@staltz Yes, that's another good reason.

Most.js in theory can be anywhere from ~200x-400x* faster than Rx 4 and still roughly 30x-50x* faster than Rx 5 so even with these conversions there should still be a performance boost where there are expensive operations like diffing and patching the DOM.

(* - https://gist.github.com/TylorS/55573b29df19c064c6b1)

Member

TylorS commented Jan 9, 2016

@staltz Yes, that's another good reason.

Most.js in theory can be anywhere from ~200x-400x* faster than Rx 4 and still roughly 30x-50x* faster than Rx 5 so even with these conversions there should still be a performance boost where there are expensive operations like diffing and patching the DOM.

(* - https://gist.github.com/TylorS/55573b29df19c064c6b1)

@Cmdv

This comment has been minimized.

Show comment
Hide comment
@Cmdv

Cmdv Jan 9, 2016

Contributor

Agreed, I'm really liking the idea to let run() handling that behind the scene and perf improvement is always a good route to take.

Also if there is a core Rx library that could fit in really nicely rather than the whole of Rx.

Would you be able to mix say Cycle-dom use most.js and run use Rx etc? I assume thats what @TylorS stream-conversions is about?

Contributor

Cmdv commented Jan 9, 2016

Agreed, I'm really liking the idea to let run() handling that behind the scene and perf improvement is always a good route to take.

Also if there is a core Rx library that could fit in really nicely rather than the whole of Rx.

Would you be able to mix say Cycle-dom use most.js and run use Rx etc? I assume thats what @TylorS stream-conversions is about?

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

@Cmdv Yes, thats the idea. The drivers can be written in x and your application will be written in whatever library you prefer.

run(main, driver, {streamLibary: 'rx'}) // write your application using RxJS
run(main, driver, {streamLibary: 'most'}) //write your application using Most.js
Member

TylorS commented Jan 9, 2016

@Cmdv Yes, thats the idea. The drivers can be written in x and your application will be written in whatever library you prefer.

run(main, driver, {streamLibary: 'rx'}) // write your application using RxJS
run(main, driver, {streamLibary: 'most'}) //write your application using Most.js
@Cmdv

This comment has been minimized.

Show comment
Hide comment
@Cmdv

Cmdv Jan 9, 2016

Contributor

Great this is a nice way to have everyone working together too 👍

Contributor

Cmdv commented Jan 9, 2016

Great this is a nice way to have everyone working together too 👍

@HighOnDrive

This comment has been minimized.

Show comment
Hide comment
@HighOnDrive

HighOnDrive Jan 9, 2016

Very nice indeed 👍

HighOnDrive commented Jan 9, 2016

Very nice indeed 👍

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 9, 2016

Member

Yes! Motorcycle will essentially will be rolled back into Cycle.js 👍

Member

TylorS commented Jan 9, 2016

Yes! Motorcycle will essentially will be rolled back into Cycle.js 👍

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 10, 2016

Member

My stream conversion library has been updated to make use of an interface to allow for easier support of additional libraries and quite a bit less code overall. Tests are now partially generated, in a way, too! I'll try to get started on a version of cycle-core that takes advantage of this, and add support for some of the common drivers. e.g. cycle-dom and cycle-http

Member

TylorS commented Jan 10, 2016

My stream conversion library has been updated to make use of an interface to allow for easier support of additional libraries and quite a bit less code overall. Tests are now partially generated, in a way, too! I'll try to get started on a version of cycle-core that takes advantage of this, and add support for some of the common drivers. e.g. cycle-dom and cycle-http

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 11, 2016

Member

I opened PR #197 for my work on stream conversions being done in run(). Drivers would now passed a function as the second parameter for use of converting between streams between different libraries.

Member

TylorS commented Jan 11, 2016

I opened PR #197 for my work on stream conversions being done in run(). Drivers would now passed a function as the second parameter for use of converting between streams between different libraries.

@Frikki

This comment has been minimized.

Show comment
Hide comment
@Frikki

Frikki Jan 11, 2016

Member

Very interesting. An idea we discussed months ago. Hopefully, I’ll soon be back working with you lot.

Member

Frikki commented Jan 11, 2016

Very interesting. An idea we discussed months ago. Hopefully, I’ll soon be back working with you lot.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz
Member

staltz commented Jan 11, 2016

@Frikki 💙

@Frikki

This comment has been minimized.

Show comment
Hide comment
@Frikki

Frikki Jan 11, 2016

Member

@cycle/dom

function domDriver(sink$) {...}

domDriver.streamAdapter = rxAdapter // mostAdapter 

I don’t understand this. Will @cycle/dom have a default rxAdapter? Or where in which file does this line appear domDriver.streamAdapter = rxAdapter? Doesn’t that create an Rx dependency? If I want to use mostAdapter, how do I do that?

UPDATE
Skip it. I am being totally stupid. Too long time off this project. Lost my marbles.

Member

Frikki commented Jan 11, 2016

@cycle/dom

function domDriver(sink$) {...}

domDriver.streamAdapter = rxAdapter // mostAdapter 

I don’t understand this. Will @cycle/dom have a default rxAdapter? Or where in which file does this line appear domDriver.streamAdapter = rxAdapter? Doesn’t that create an Rx dependency? If I want to use mostAdapter, how do I do that?

UPDATE
Skip it. I am being totally stupid. Too long time off this project. Lost my marbles.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 11, 2016

Member

@TylorS we need to rename some things in the Adapter interface:

 interface Adapter {
-  replaySubject(): any;
+  makeHoldSubject(): any;
   dispose(sinks: any, sinkProxies: any, sources: any): void;
-  replicate(stream: any, sink: Sink): void;
+  replicate(stream: any, observer: Observer): void;
-  isAdaptedStream(stream: any): boolean;
+  isValidStream(stream: any): boolean;
-  streamSubscription(stream: any, sink: Sink): void;
+  subscribeToStream(stream: any, observer: Observer): Disposable;
-  adaptation(fromStream: any, fromStreamSubscriptionFunc: Function): any;
+  adapt(originStream: any, subscribeToOriginStream: Function): any;
}

And the Sink type to be renamed to Observer (it's important that its name doesn't clash with driver sink/source):

-interface Sink {
+interface Observer<T> {
-  add(x: any): void;
+  next(x: any): void;
   error(e: any): void;
-  end(): void;
+  complete(): void;
}

^ Names next/error/complete above are from ES7 Observable.

Member

staltz commented Jan 11, 2016

@TylorS we need to rename some things in the Adapter interface:

 interface Adapter {
-  replaySubject(): any;
+  makeHoldSubject(): any;
   dispose(sinks: any, sinkProxies: any, sources: any): void;
-  replicate(stream: any, sink: Sink): void;
+  replicate(stream: any, observer: Observer): void;
-  isAdaptedStream(stream: any): boolean;
+  isValidStream(stream: any): boolean;
-  streamSubscription(stream: any, sink: Sink): void;
+  subscribeToStream(stream: any, observer: Observer): Disposable;
-  adaptation(fromStream: any, fromStreamSubscriptionFunc: Function): any;
+  adapt(originStream: any, subscribeToOriginStream: Function): any;
}

And the Sink type to be renamed to Observer (it's important that its name doesn't clash with driver sink/source):

-interface Sink {
+interface Observer<T> {
-  add(x: any): void;
+  next(x: any): void;
   error(e: any): void;
-  end(): void;
+  complete(): void;
}

^ Names next/error/complete above are from ES7 Observable.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 11, 2016

Member

@Frikki drivers will be written always in a specific stream library, so they will have a peerDependency on that stream library. That snippet of code was meant to be library code, not user land code.

Member

staltz commented Jan 11, 2016

@Frikki drivers will be written always in a specific stream library, so they will have a peerDependency on that stream library. That snippet of code was meant to be library code, not user land code.

@TylorS

This comment has been minimized.

Show comment
Hide comment
@TylorS

TylorS Jan 11, 2016

Member

@staltz Yes, we should definitely work to standardize the interface further. I'm okay with the changes you propose.

@Frikki any thoughts on them?

Member

TylorS commented Jan 11, 2016

@staltz Yes, we should definitely work to standardize the interface further. I'm okay with the changes you propose.

@Frikki any thoughts on them?

@Frikki

This comment has been minimized.

Show comment
Hide comment
@Frikki

Frikki Jan 11, 2016

Member

After reviewing functional programming standards, verbs denote referentially transparent functions, and nouns denote immutable data. So I guess I am fine with the changes. But can I see the current adapter interface file? Where does it live?

UPDATE
makeHoldSubject is defined in the proposed interface to return any type, but is that correct? Doesn’t it always return an object? @staltz ?

Member

Frikki commented Jan 11, 2016

After reviewing functional programming standards, verbs denote referentially transparent functions, and nouns denote immutable data. So I guess I am fine with the changes. But can I see the current adapter interface file? Where does it live?

UPDATE
makeHoldSubject is defined in the proposed interface to return any type, but is that correct? Doesn’t it always return an object? @staltz ?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 12, 2016

Member

@Frikki there isn't the "object" type in TypeScript.

Member

staltz commented Jan 12, 2016

@Frikki there isn't the "object" type in TypeScript.

@Frikki

This comment has been minimized.

Show comment
Hide comment
@Frikki

Frikki Jan 12, 2016

Member

@staltz Ha ha. Didn’t know that. Would it then be more correct

interface HoldSubject {
  observer: Observer,
  stream: any
}

and in interface Adapter

makeHoldSubject(): HoldSubject

?

Member

Frikki commented Jan 12, 2016

@staltz Ha ha. Didn’t know that. Would it then be more correct

interface HoldSubject {
  observer: Observer,
  stream: any
}

and in interface Adapter

makeHoldSubject(): HoldSubject

?

@Frikki

This comment has been minimized.

Show comment
Hide comment
@Frikki

Frikki Jan 12, 2016

Member

@staltz Could you put a README file in the base repo, so we can fork it and make PRs? Many thanks.

Member

Frikki commented Jan 12, 2016

@staltz Could you put a README file in the base repo, so we can fork it and make PRs? Many thanks.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 12, 2016

Member

Sure thing. About the HoldSubject interface, that's correct. And as you can see you can indefinitely start giving more and more types.

Member

staltz commented Jan 12, 2016

Sure thing. About the HoldSubject interface, that's correct. And as you can see you can indefinitely start giving more and more types.

@SteveALee

This comment has been minimized.

Show comment
Hide comment
@SteveALee

SteveALee Mar 13, 2016

Contributor

PS Netflix mention the concept of the 'Paved Road' for the most common and best supported developer tooling. I like that and think it fits here too. We have the paved road but devs are free to go off road if they like as long as they accept the extra work that it might involve.

Contributor

SteveALee commented Mar 13, 2016

PS Netflix mention the concept of the 'Paved Road' for the most common and best supported developer tooling. I like that and think it fits here too. We have the paved road but devs are free to go off road if they like as long as they accept the extra work that it might involve.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Mar 14, 2016

Member

Yes @SteveALee our plan is to precisely give a reasonable default option to the developer, so she doesn't need to pick/choose when starting a project. This is after all a framework, not a library. But we also want to give developers freedom of some choice, without being an obstacle in their way.

Member

staltz commented Mar 14, 2016

Yes @SteveALee our plan is to precisely give a reasonable default option to the developer, so she doesn't need to pick/choose when starting a project. This is after all a framework, not a library. But we also want to give developers freedom of some choice, without being an obstacle in their way.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Mar 14, 2016

Member

PS: please don't post 👍 comments, ever. There is now the reactions feature in GitHub, so just use that. Thanks and sorry for being curt about it.

Member

staltz commented Mar 14, 2016

PS: please don't post 👍 comments, ever. There is now the reactions feature in GitHub, so just use that. Thanks and sorry for being curt about it.

@SteveALee

This comment has been minimized.

Show comment
Hide comment
@SteveALee

SteveALee Mar 14, 2016

Contributor

Sure, I would have but stupidly they are not available on the github mobile Web app. :(

Contributor

SteveALee commented Mar 14, 2016

Sure, I would have but stupidly they are not available on the github mobile Web app. :(

@laszlokorte

This comment has been minimized.

Show comment
Hide comment
@laszlokorte

laszlokorte Apr 8, 2016

Contributor

Shouldn't DOMSource.select().element$ be called DOMSource.select().elements$ because the stream does not contain only one element but an array of matching elements?

Contributor

laszlokorte commented Apr 8, 2016

Shouldn't DOMSource.select().element$ be called DOMSource.select().elements$ because the stream does not contain only one element but an array of matching elements?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Apr 8, 2016

Member

Perhaps it should. We're also considering renaming events => event$. These two things would make the dollar convention official, as opposed to optional as it was before.

Member

staltz commented Apr 8, 2016

Perhaps it should. We're also considering renaming events => event$. These two things would make the dollar convention official, as opposed to optional as it was before.

@creatorrr

This comment has been minimized.

Show comment
Hide comment
@creatorrr

creatorrr Apr 13, 2016

Would be great to get started writing docs and examples for writing stream adapters. Is the API stable enough for that?

creatorrr commented Apr 13, 2016

Would be great to get started writing docs and examples for writing stream adapters. Is the API stable enough for that?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Apr 13, 2016

Member

No, not yet. We might change some things with stream adapters. And I'm not sure we need even docs for that. There's only a handful of stream libraries, and we don't want Cycle.js users to feel like they need to know about stream adapters. In fact, it's a framework-internal thing and they shouldn't need to know about it.

Member

staltz commented Apr 13, 2016

No, not yet. We might change some things with stream adapters. And I'm not sure we need even docs for that. There's only a handful of stream libraries, and we don't want Cycle.js users to feel like they need to know about stream adapters. In fact, it's a framework-internal thing and they shouldn't need to know about it.

@creatorrr

This comment has been minimized.

Show comment
Hide comment
@creatorrr

creatorrr Apr 13, 2016

I see. Although, given that Web-streams will be shipping natively in browsers soon, we could safely assume a deluge of higher level streams libraries.

creatorrr commented Apr 13, 2016

I see. Although, given that Web-streams will be shipping natively in browsers soon, we could safely assume a deluge of higher level streams libraries.

@whitecolor

This comment has been minimized.

Show comment
Hide comment
@whitecolor

whitecolor Apr 26, 2016

Contributor

Web-streams will be shipping natively in browsers soon

yes, like observers, ES7, http2.. soon

Contributor

whitecolor commented Apr 26, 2016

Web-streams will be shipping natively in browsers soon

yes, like observers, ES7, http2.. soon

@SteveALee

This comment has been minimized.

Show comment
Hide comment
@SteveALee

SteveALee Apr 26, 2016

Contributor

heh, and don't forget web components.

Contributor

SteveALee commented Apr 26, 2016

heh, and don't forget web components.

@tusharmath

This comment has been minimized.

Show comment
Hide comment
@tusharmath

tusharmath May 14, 2016

Here is another thought, how about the API being exposed via simple callbacks or event emitters. This would make the API much simpler to consume and convert to whichever stream people want to use. This would also encourage people to write truly stream agnostic drivers which is a must have.

tusharmath commented May 14, 2016

Here is another thought, how about the API being exposed via simple callbacks or event emitters. This would make the API much simpler to consume and convert to whichever stream people want to use. This would also encourage people to write truly stream agnostic drivers which is a must have.

@whitecolor

This comment has been minimized.

Show comment
Hide comment
@whitecolor

whitecolor May 14, 2016

Contributor

@tusharmath what API? you actually may use adapter's API to create lib agnostic drivers. It is probably not perfect for this task, but basic cases can be implemented quite easily.

Contributor

whitecolor commented May 14, 2016

@tusharmath what API? you actually may use adapter's API to create lib agnostic drivers. It is probably not perfect for this task, but basic cases can be implemented quite easily.

@tusharmath

This comment has been minimized.

Show comment
Hide comment
@tusharmath

tusharmath May 15, 2016

@whitecolor

which api

The Cycle.run method could actually get rid of any dependency on a stream lib completely. The same applies to @cycle/dom

Here are my concerns in detail —

  • I am using most.js for my application but I still need to have a copy of the humungous RxJS lib simply because Cycle depends on it. IMHO letting go of Rx or any other streaming lib will make cycle easier to adopt and also not be limited by the performance of that streaming lib. Every now and then there is going to be something faster and its not realistic to expect Cycle and its drivers to immediately upgrade.
  • Cycle is about following a MVI pattern but should not be enforcing FRP as a way to achieve it. FRP makes literally everything easier, but that should not become a criteria for how Cycle's interface is designed.

tusharmath commented May 15, 2016

@whitecolor

which api

The Cycle.run method could actually get rid of any dependency on a stream lib completely. The same applies to @cycle/dom

Here are my concerns in detail —

  • I am using most.js for my application but I still need to have a copy of the humungous RxJS lib simply because Cycle depends on it. IMHO letting go of Rx or any other streaming lib will make cycle easier to adopt and also not be limited by the performance of that streaming lib. Every now and then there is going to be something faster and its not realistic to expect Cycle and its drivers to immediately upgrade.
  • Cycle is about following a MVI pattern but should not be enforcing FRP as a way to achieve it. FRP makes literally everything easier, but that should not become a criteria for how Cycle's interface is designed.
@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz May 15, 2016

Member

@tusharmath There will be a Cycle.run for each stream library, e.g. @cycle/rx-run, @cycle/most-run etc. Cycle Diversity is about making these libraries with each other so that if you have a driver written in most, you can use it even though your app is in Rx. But the endgoal with all this is to gradually and softly migrate to xstream. If we had started from the beginning with xstream, Cycle Diversity and the interop between these stream libraries would not be necessary.

Member

staltz commented May 15, 2016

@tusharmath There will be a Cycle.run for each stream library, e.g. @cycle/rx-run, @cycle/most-run etc. Cycle Diversity is about making these libraries with each other so that if you have a driver written in most, you can use it even though your app is in Rx. But the endgoal with all this is to gradually and softly migrate to xstream. If we had started from the beginning with xstream, Cycle Diversity and the interop between these stream libraries would not be necessary.

@Cmdv

This comment has been minimized.

Show comment
Hide comment
@Cmdv

Cmdv May 15, 2016

Contributor

@staltz is the long term goal, to have xstream be the only streaming library involved?

Contributor

Cmdv commented May 15, 2016

@staltz is the long term goal, to have xstream be the only streaming library involved?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz May 15, 2016

Member

I don't mean we will cut support for other libraries. That's not the point. The point is that xstream is meant for Cycle and Cycle for xstream.

Member

staltz commented May 15, 2016

I don't mean we will cut support for other libraries. That's not the point. The point is that xstream is meant for Cycle and Cycle for xstream.

@whitecolor

This comment has been minimized.

Show comment
Hide comment
@whitecolor

whitecolor May 15, 2016

Contributor

But the endgoal with all this is to gradually and softly migrate to xstream. If we had started from the beginning with xstream, Cycle Diversity and the interop between these stream libraries would not be necessary.

I can not completely agree with this. I believe cycle has potential of staying/becoming really stream library agnostic framework, and no need to set this restricting "endgoal". I believe @cycle/core will become eventually xstream-run instead of rx-run, but time will show if Cycle for xstream (sounds kinda nazy) is better vision than real diversity.

Though I can not disagree that dealing with one universal stream library is simpler and eventually better approach - but this should be very natural way of coming to this point.

@tusharmath for using components that were developed with different stream libs I've created #305

Contributor

whitecolor commented May 15, 2016

But the endgoal with all this is to gradually and softly migrate to xstream. If we had started from the beginning with xstream, Cycle Diversity and the interop between these stream libraries would not be necessary.

I can not completely agree with this. I believe cycle has potential of staying/becoming really stream library agnostic framework, and no need to set this restricting "endgoal". I believe @cycle/core will become eventually xstream-run instead of rx-run, but time will show if Cycle for xstream (sounds kinda nazy) is better vision than real diversity.

Though I can not disagree that dealing with one universal stream library is simpler and eventually better approach - but this should be very natural way of coming to this point.

@tusharmath for using components that were developed with different stream libs I've created #305

@edge

This comment has been minimized.

Show comment
Hide comment
@edge

edge May 15, 2016

@whitecolor Diversity is cool and all, but if we want to have minimal bundle sizes and maximum performance, then sticking to one stream implementation is the way to go.

The last thing we want to do is to send the client a >1 MB distribution including xstream, rx4, rx5, most, bacon, and kefir just because we flaunted the ability to choose whatever stream library suited your fancy.

edge commented May 15, 2016

@whitecolor Diversity is cool and all, but if we want to have minimal bundle sizes and maximum performance, then sticking to one stream implementation is the way to go.

The last thing we want to do is to send the client a >1 MB distribution including xstream, rx4, rx5, most, bacon, and kefir just because we flaunted the ability to choose whatever stream library suited your fancy.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz May 15, 2016

Member

@edge Not just that, but having more choices leads to more choice paralysis for beginner programmers, but it also means more maintenance for the core developers. I am building Cycle as a framework with smart defaults, but with some degree of choice/freedom, not as a generic layer for everything anyone wants.

Member

staltz commented May 15, 2016

@edge Not just that, but having more choices leads to more choice paralysis for beginner programmers, but it also means more maintenance for the core developers. I am building Cycle as a framework with smart defaults, but with some degree of choice/freedom, not as a generic layer for everything anyone wants.

@whitecolor

This comment has been minimized.

Show comment
Hide comment
@whitecolor

whitecolor May 15, 2016

Contributor

@edge nothing restricts you from this with diversity approach. Use drivers and components written with your library of choice.

And I agree that xstream can become a good standard for shared components. But i'm also convinced that harmonic approach to diversity will only make framework stronger.

@staltz

but it also means more maintenance for the core developers

Not always, it depends on chosen approach - if generalized approach is chosen correctly, it will make framework and tools even less prone to errors for specific cases eventually.

Contributor

whitecolor commented May 15, 2016

@edge nothing restricts you from this with diversity approach. Use drivers and components written with your library of choice.

And I agree that xstream can become a good standard for shared components. But i'm also convinced that harmonic approach to diversity will only make framework stronger.

@staltz

but it also means more maintenance for the core developers

Not always, it depends on chosen approach - if generalized approach is chosen correctly, it will make framework and tools even less prone to errors for specific cases eventually.

@download13

This comment has been minimized.

Show comment
Hide comment
@download13

download13 Jun 9, 2016

I'm curious why xstream was chosen over something that could be more interoperable like es-observable`.

If the spec is added to a future version of JavaScript we'll likely have a built-in implementation of Observable that all libraries can use (much like Promise). At that point libraries will only need to depend on utility functions, which can be imported as bundles (a la rx) if they don't mind being bulky or individually (something like @cycle/flatMapLatest).

download13 commented Jun 9, 2016

I'm curious why xstream was chosen over something that could be more interoperable like es-observable`.

If the spec is added to a future version of JavaScript we'll likely have a built-in implementation of Observable that all libraries can use (much like Promise). At that point libraries will only need to depend on utility functions, which can be imported as bundles (a la rx) if they don't mind being bulky or individually (something like @cycle/flatMapLatest).

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 9, 2016

Member

I am closely following es-observable closely and I am involved in discussions. For now, it is a moving target. We are building Cycle Diversity with tools from today, not from tomorrow.

Member

staltz commented Jun 9, 2016

I am closely following es-observable closely and I am involved in discussions. For now, it is a moving target. We are building Cycle Diversity with tools from today, not from tomorrow.

@staltz

This comment has been minimized.

Show comment
Hide comment
Member

staltz commented Jun 29, 2016

@mightyiam

This comment has been minimized.

Show comment
Hide comment
@mightyiam

mightyiam Jun 29, 2016

Yay! Good job!

mightyiam commented Jun 29, 2016

Yay! Good job!

staltz pushed a commit that referenced this issue Jul 18, 2016

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