The implementation of the Scan operator differs between Ix (both sync and async) and Rx with regards to the first element.
The source code contains a comment explaining the behavior for Ix stating it's compatible with Rx (but that's not actually the case):
// NB: Implementations of Scan never yield the first element, unlike the behavior of Aggregate on a sequence with one
// element, which returns the first element (or the seed if given an empty sequence). This is compatible with Rx
// but one could argue whether it was the right default.
This test code demonstrates the issue:
var ob = Enumerable.Range(0, 3).ToObservable();
var ae = Enumerable.Range(0, 3).ToAsyncEnumerable();
var obResult = await ob.Scan((acc, i) => i).ToList(); // 0, 1, 2
var aeResult = await ae.Scan((acc, i) => i).ToListAsync(); // 1, 2
var isSame = aeResult.SequenceEqual(obResult); // false
Furthermore, the implementation of Scan in MoreLINQ yield the first element, adding to the confusion when switching between libraries.
I understand that it's less than ideal to change the behavior of existing operators, but in this case I think it's worth considering due to the current inconsistency.
I would be happy to make a PR if you agree it should be changed.
The implementation of the
Scanoperator differs between Ix (both sync and async) and Rx with regards to the first element.The source code contains a comment explaining the behavior for Ix stating it's compatible with Rx (but that's not actually the case):
This test code demonstrates the issue:
Furthermore, the implementation of
Scanin MoreLINQ yield the first element, adding to the confusion when switching between libraries.I understand that it's less than ideal to change the behavior of existing operators, but in this case I think it's worth considering due to the current inconsistency.
I would be happy to make a PR if you agree it should be changed.