Skip to content

scan operator description might be confusing when not using any seed #4348

@martinsik

Description

@martinsik

Documentation Related To Component:

scan

Please check those that apply

  • typo
  • documentation doesn't exist
  • documentation needs clarification
  • error(s) in example
  • needs example

Description Of The Issue

The last paragraph in scan's docblock says (emphasis is mine):

Returns an Observable that applies a specified accumulator function to each item emitted by the source Observable. If a seed value is specified, then that value will be used as the initial value for the accumulator. If no seed value is specified, the first item of the source is used as the seed.

However, the actual scan behavior isn't exactly like this:

...applies a specified accumulator function to each item emitted by the source Observable

It doesn't apply the accumulator function to every item if I don't set any seed. In that case it just passes the first emission through without calling accumulator:

from(['a', 'b', 'c']).pipe(
  scan<string, number>((acc, value, index) => {
    console.log(value, index);
    return 0;
  }),
).subscribe();

This will make the following output even when the first item was "a":

b 0
c 1

This is the relevant code:

protected _next(value: T): void {
if (!this.hasSeed) {
this.seed = value;
this.destination.next(value);
} else {
return this._tryNext(value);
}
}

Demo: https://stackblitz.com/edit/rxjs6-demo-ynfnan

So even though the sequence started with "a" the accumulator function was called for the first time for "b". Also the index passed started at 0 for the second item (does index count how many times the function was called or does it count the number of items that went through this operator?).

the first item of the source is used as the seed.

From the last sentence I would guess that the accumulator function will be called even for the first value like this order (even though it is a little weird):

accumulator('a', 'a', 0);
accumulator(..., 'b', 1);
accumulator(..., 'c', 2);

... while in fact it's called like this:

accumulator('a', 'b', 0);
accumulator(..., 'c', 1);

So maybe I'm just dumb but the description and actual behavior without setting any seed really confused me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsIssues and PRs related to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions