Skip to content

Commit

Permalink
fix(core): remove instance combine() and merge()
Browse files Browse the repository at this point in the history
We already have static xs.combine() and xs.merge(). The value of instance stream.merge()/combine()
is questionable, specially given that we have not seen those usages that often in real code. This
commit simple removes instance merge and combine.

BREAKING CHANGE:
Instance operators stream.combine() and stream.merge() removed. Use
xs.combine() and xs.merge() instead.
  • Loading branch information
staltz committed Jun 3, 2016
1 parent 116e9f2 commit 00fc72c
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 290 deletions.
67 changes: 7 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ var xs = require('xstream').default

## Methods and Operators

- [`combine`](#combine)
- [`addListener`](#addListener)
- [`removeListener`](#removeListener)
- [`map`](#map)
Expand All @@ -96,7 +95,6 @@ var xs = require('xstream').default
- [`fold`](#fold)
- [`replaceError`](#replaceError)
- [`flatten`](#flatten)
- [`merge`](#merge)
- [`compose`](#compose)
- [`remember`](#remember)
- [`debug`](#debug)
Expand Down Expand Up @@ -463,39 +461,6 @@ streams.

Methods are functions attached to a Stream instance, like `stream.addListener()`. Operators are also methods, but return a new Stream, leaving the existing Stream unmodified, except for the fact that it has a child Stream attached as Listener.

### <a id="combine"></a> `combine(project, other)`

Combines multiple streams with the input stream to return a stream whose
events are calculated from the latest events of each of its input streams.

*combine* remembers the most recent event from each of the input streams.
When any of the input streams emits an event, that event together with all
the other saved events are combined in the `project` function which should
return a value. That value will be emitted on the output stream. It's
essentially a way of mixing the events from multiple streams according to a
formula.

Marble diagram:

```text
--1----2-----3--------4---
----a-----b-----c--d------
combine((x,y) => x+y)
----1a-2a-2b-3b-3c-3d-4d--
```

#### Arguments:

- `project: Function` A function of type `(x: T1, y: T2) => R` or similar that takes the most recent events `x` and `y` from the input
streams and returns a value. The output stream will emit that value. The
number of arguments for this function should match the number of input
streams.
- `other: Stream` Another stream to combine together with the input stream. There may be more of these arguments.

#### Returns: Stream

- - -

### <a id="addListener"></a> `addListener(listener)`

Adds a Listener to the Stream.
Expand Down Expand Up @@ -778,30 +743,6 @@ Marble diagram:

- - -

### <a id="merge"></a> `merge(other)`

Blends two streams together, emitting events from both.

*merge* takes an `other` stream and returns an output stream that imitates
both the input stream and the `other` stream.

Marble diagram:

```text
--1----2-----3--------4---
----a-----b----c---d------
merge
--1-a--2--b--3-c---d--4---
```

#### Arguments:

- `other: Stream` Another stream to merge together with the input stream.

#### Returns: Stream

- - -

### <a id="compose"></a> `compose(operator)`

Passes the input stream to a custom operator, to produce an output stream.
Expand Down Expand Up @@ -909,7 +850,7 @@ given `other` stream.

#### Arguments:

- `other: Stream` The stream to imitate on the current one.
- `other: Stream` The stream to imitate on the current one. Must not be a MemoryStream.

- - -

Expand All @@ -919,6 +860,12 @@ The operators and factories listed above are the core functions. `xstream` has p

# FAQ

**Q: Why does `imitate()` support a Stream but not a MemoryStream?**

A: MemoryStreams are meant for representing "values over time" (your age), while Streams represent simply events (your birthdays). MemoryStreams are usually initialized with a value, and `imitate()` is meant for creating circular dependencies of streams. If we would attempt to imitate a MemoryStream in a circular dependency, we would either get a race condition (where the symptom would be "nothing happens") or an infinite cyclic emission of values.

If you find yourself wanting to use `imitate()` with a MemoryStream, you should rework your code around `imitate()` to use a Stream instead. Look for the stream in the circular dependency that represents an event stream, and that would be a candidate for creating a MimicStream which then imitates the real event stream.

**Q: What's the difference between xstream and RxJS?**

A: Read this [blog post](http://staltz.com/why-we-built-xstream.html) on the topic.
Expand Down
17 changes: 3 additions & 14 deletions dist/xstream.js
Original file line number Diff line number Diff line change
Expand Up @@ -845,15 +845,6 @@ exports.TakeOperator = TakeOperator;
var Stream = (function () {
function Stream(producer) {
this._stopID = empty;

this.combine = function combine(project) {
var streams = [];
for (var _i = 1; _i < arguments.length; _i++) {
streams[_i - 1] = arguments[_i];
}
streams.unshift(this);
return Stream.combine.apply(Stream, [project].concat(streams));
};
this._prod = producer;
this._ils = [];
}
Expand Down Expand Up @@ -1080,10 +1071,6 @@ var Stream = (function () {
new FlattenOperator(this));
};

Stream.prototype.merge = function (other) {
return Stream.merge(this, other);
};

Stream.prototype.compose = function (operator) {
return operator(this);
};
Expand Down Expand Up @@ -1142,7 +1129,9 @@ var MimicStream = (function (_super) {

MimicStream.prototype.imitate = function (other) {
if (other instanceof MemoryStream) {
throw new Error('bad');
throw new Error('A MemoryStream was given to imitate(), but it only ' +
'supports a Stream. Read more about this restriction here: ' +
'https://github.com/staltz/xstream#faq');
}
this._target = other;
};
Expand Down
2 changes: 1 addition & 1 deletion dist/xstream.min.js

Large diffs are not rendered by default.

81 changes: 0 additions & 81 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,28 +121,6 @@ export interface CombineFactorySignature {
<R>(project: (...args: Array<any>) => R, ...streams: Array<Stream<any>>): Stream<R>;
}

export interface CombineInstanceSignature<T> {
<T2, R>(
project: (t1: T, t2: T2) => R,
stream2: Stream<T2>): Stream<R>;
<T2, T3, R>(
project: (t1: T, t2: T2, t3: T3) => R,
stream2: Stream<T2>,
stream3: Stream<T3>): Stream<R>;
<T2, T3, T4, R>(
project: (t1: T, t2: T2, t3: T3, t4: T4) => R,
stream2: Stream<T2>,
stream3: Stream<T3>,
stream4: Stream<T4>): Stream<R>;
<T2, T3, T4, T5, R>(
project: (t1: T, t2: T2, t3: T3, t4: T4, t5: T5) => R,
stream2: Stream<T2>,
stream3: Stream<T3>,
stream4: Stream<T4>,
stream5: Stream<T5>): Stream<R>;
<R>(project: (...args: Array<any>) => R, ...streams: Array<Stream<any>>): Stream<R>;
}

export class CombineListener<T> implements InternalListener<T> {
constructor(private i: number,
private p: CombineProducer<T>) {
Expand Down Expand Up @@ -1594,65 +1572,6 @@ export class Stream<T> implements InternalListener<T> {
);
}

/**
* Blends two streams together, emitting events from both.
*
* *merge* takes an `other` stream and returns an output stream that imitates
* both the input stream and the `other` stream.
*
* Marble diagram:
*
* ```text
* --1----2-----3--------4---
* ----a-----b----c---d------
* merge
* --1-a--2--b--3-c---d--4---
* ```
*
* @param {Stream} other Another stream to merge together with the input
* stream.
* @return {Stream}
*/
merge(other: Stream<T>): Stream<T> {
return Stream.merge(this, other);
}

/**
* Combines multiple streams with the input stream to return a stream whose
* events are calculated from the latest events of each of its input streams.
*
* *combine* remembers the most recent event from each of the input streams.
* When any of the input streams emits an event, that event together with all
* the other saved events are combined in the `project` function which should
* return a value. That value will be emitted on the output stream. It's
* essentially a way of mixing the events from multiple streams according to a
* formula.
*
* Marble diagram:
*
* ```text
* --1----2-----3--------4---
* ----a-----b-----c--d------
* combine((x,y) => x+y)
* ----1a-2a-2b-3b-3c-3d-4d--
* ```
*
* @param {Function} project A function of type `(x: T1, y: T2) => R` or
* similar that takes the most recent events `x` and `y` from the input
* streams and returns a value. The output stream will emit that value. The
* number of arguments for this function should match the number of input
* streams.
* @param {Stream} other Another stream to combine together with the input
* stream. There may be more of these arguments.
* @return {Stream}
*/
combine: CombineInstanceSignature<T> =
function combine<R>(project: CombineProjectFunction,
...streams: Array<Stream<any>>): Stream<R> {
streams.unshift(this);
return Stream.combine(project, ...streams);
};

/**
* Passes the input stream to a custom operator, to produce an output stream.
*
Expand Down
18 changes: 17 additions & 1 deletion tests/factory/combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('xs.combine', () => {
stop: () => {}
});

const combined = xs.combine(
const combined: Stream<string> = xs.combine(
(a, b) => a.slice(2) + b.slice(2),
stream1, stream2
);
Expand Down Expand Up @@ -146,4 +146,20 @@ describe('xs.combine', () => {
},
});
});

it('should return a Stream when combining a MemoryStream with a Stream', (done) => {
const input1 = xs.periodic(50).take(4).remember();
const input2 = xs.periodic(80).take(3);
const stream: Stream<number> = xs.combine((x, y) => x + y, input1, input2);
assert.strictEqual(stream instanceof Stream, true);
done();
});

it('should return a Stream when combining a MemoryStream with a MemoryStream', (done) => {
const input1 = xs.periodic(50).take(4).remember();
const input2 = xs.periodic(80).take(3).remember();
const stream: Stream<number> = xs.combine((x, y) => x + y, input1, input2);
assert.strictEqual(stream instanceof Stream, true);
done();
});
});
18 changes: 17 additions & 1 deletion tests/factory/merge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference path="../../typings/globals/mocha/index.d.ts" />
/// <reference path="../../typings/globals/node/index.d.ts" />
import xs from '../../src/index';
import xs, {Stream} from '../../src/index';
import * as assert from 'assert';

describe('xs.merge', () => {
Expand Down Expand Up @@ -38,4 +38,20 @@ describe('xs.merge', () => {
},
});
});

it('should return a Stream when merging a MemoryStream with a Stream', (done) => {
const input1 = xs.periodic(50).take(4).remember();
const input2 = xs.periodic(80).take(3);
const stream: Stream<number> = xs.merge(input1, input2);
assert.strictEqual(stream instanceof Stream, true);
done();
});

it('should return a Stream when merging a MemoryStream with a MemoryStream', (done) => {
const input1 = xs.periodic(50).take(4).remember();
const input2 = xs.periodic(80).take(3).remember();
const stream: Stream<number> = xs.merge(input1, input2);
assert.strictEqual(stream instanceof Stream, true);
done();
});
});
75 changes: 0 additions & 75 deletions tests/operator/combine.ts

This file was deleted.

Loading

0 comments on commit 00fc72c

Please sign in to comment.