Giter VIP home page Giter VIP logo

Comments (8)

jeffbcross avatar jeffbcross commented on May 12, 2024

A modular Observable would also be nice for frameworks (including Angular).

Perhaps a good approach to number 3 would be to leave it up to the developer to explicitly handle decoration (with a helper method on Observable), and operators could be written as functions that expect to be called with context, which would fit nicely within the bind_operator ES proposal.

//map.js
export function map () {
  // this == Observable instance
  return new MapObservable(this);
}
//mymodule.js
import {Observable} from 'rx';
import {map} from './map';
//Plain old call
var observable = new Observable(...);
map.call(observable, (val) => val).subscribe(...);

//Decorate Observable
var MyObservable = Observable.decorateFrom(map);
(new MyObservable(...)).map(val => val).subscribe(...);

//Bind_operator style (I think)
(new Observable(...))::map(val => val).subscribe(...);

Whatever the solution to number 3, I think it's important for the "global" Rx object to be treated as immutable, and more explicitly decorated by the user. The best practice for app developers could be to create a module with the Rx object decorated with common operators for an application, which could be further decorated as needed by other parts of the application. Distributions like rx.lite and rx.all could also use this approach to have distributions with common operators, for users who aren't as byte-sensitive.

What do you think @trxcllnt? + @vsavkin

from rxjs.

jeffbcross avatar jeffbcross commented on May 12, 2024

My "Decorate Observable" proposal is flawed, since there are many Observable subclasses. Decorating a copy of Observable would require other implementations, like MapObservable, to know about the decorated prototype they should be inheriting.

from rxjs.

trxcllnt avatar trxcllnt commented on May 12, 2024

@jeffbcross I've used the convention that the source Observable is the last argument to an operator, but the operator can default to this, for example:

// src/operators/map.js
module.exports = function map(project, source) {
  return new MapObservable(source || this, project);
};

However, this is in direct conflict with another feature I've been hoping to support: maintaining Observable subtypes through the chain. If an operator returns a subclass of Observable, subsequent operators should return the same subclass.

If we can ensure this, we won't need to save out the Observables from operators that return subtypes, like multicast, to interact with them later. It will also make subclassing and adding your own Observable operators possible.

For operators, each Observable subclass is essentially just a factory that proxies the operator arguments to the operator-specific Generator subclass. If the Observable constructor accepts source, generatorFactory, and generatorArguments, the operator can delegate Generator creation to the source Observable's constructor:

// src/Observable.js
var Generator = require("rx/Generator");
function Observable(source, generatorFactory, generatorArguments) {
  this.source = source;
  this.generatorFactory = generatorFactory;
  this.generatorArguments = generatorArguments || [];
}
Observable.prototype.constructor = Observable;
Observable.prototype.subscribe = function subscribe(_next, _throw, _return) {
  if(_next && typeof _next === "object") {
    return this._subscribe(_next);
  }
  return this._subscribe(new Generator(_next, _throw, _return);
};
Observable.prototype._subscribe = function _subscribe(generator) {
  var generator2 = this.generatorFactory.apply(generator, this.generatorArguments);
  var subscription = this.source.subscribe(generator2);
  switch(typeof subscription) {
    case "function":
        return Generator.return(subscription);
    case "object":
        return subscription || Generator.empty();
    default:
        return Generator.empty();
  }
}
// src/operators/map.js
var Generator = require("rx/Generator");

function MapGeneratorFactory(project) {
  return new MapGenerator(this, project);
}

function MapGenerator(destination, project) {
  this.project = project;
  Generator.call(this, destination);
}

MapGenerator.prototype = Object.create(Generator.prototype);

MapGenerator.prototype._next = function _next(value) {
  return this.destination.next(this.project(value));
}

module.exports = function map(project, source) {
  return new (source || (source = this)).constructor(source, MapGeneratorFactory, [project]);
}

from rxjs.

benlesh avatar benlesh commented on May 12, 2024

I've used the convention that the source Observable is the last argument to an operator

I have (perhaps unfounded) concerns about adding too many optional arguments to our methods, and how that will affect the optimization of the library. It seems like in doing so we'll be creating a lot of polymorphic functions. That might be okay, if they all have monomorphic functions backing them, but that could end up bloating the library too.

Food for thought.

from rxjs.

benlesh avatar benlesh commented on May 12, 2024

I think we've got a good approach for this at the moment.

Right now we have each operator in it's own module, so if you're using a build system or a module system, you can reference those directly and get the desired effect. Also, I'm a big fan of the ES function bind proposal that @jeffbcross pointed out. It's already available in Babel, and hopefully the TypeScript people get on the ball with that. We don't need it, of course.

from rxjs.

calebboyd avatar calebboyd commented on May 12, 2024

@trxcllnt I'd be interested in knowing if you are still pursuing the idea of maintaining Observable subtypes through the chain or if it has been dropped. I dabbled with this idea using lodash's chaining mechanism but I don't think it was ready to be externalized.

from rxjs.

benlesh avatar benlesh commented on May 12, 2024

@calebboyd it has been dropped for now. There really isn't any prior art for maintaining a custom type through a fluent method chain. The ES7 function bind feature is more than enough to help most people's needs for chaining custom functions.

The major thing that killed this feature is that once native Observables land in-browser, ideally this whole library becomes a set of extension methods built on top of that. As people have learned with Promises, the in-browser Promise debugger only works with native Promises, and not Promises from libraries. Future tooling for Observable is likely to be the same.

This library is still pre-alpha though, so if consensus changes, we'll change it back.

from rxjs.

calebboyd avatar calebboyd commented on May 12, 2024

Thanks @Blesh for replying. I agree the :: syntax is convenient. I almost wish there was something explicit like that for other language's extension methods (C#).

As for prior art, I'm not sure this pattern exists in JS, but Scala supports similar behavior with this.type (mutable chains) and cough* Java, also has co-variant return types.

-- I'll keep watching, exited to see where this library is headed.

from rxjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.