I think this is a general thing with sodium, though the code sample below is typescript
The docs state that hold() is delayed untill the end of a transaction, so any gate() that relies on that hold will actually be using the value from the previous transaction. (please correct me if I'm wrong about that or if there's a better way of clarifying it)
Consider:
import { Cell, Stream, StreamSink, Transaction } from "sodiumjs";
const MIN = 2;
const MAX = 10;
function validate(n): boolean {
return (n >= MIN && n <= MAX);
}
class Test {
protected sUpdate:StreamSink<number>;
protected sValidated:Stream<number>;
constructor(label:string) {
console.log("---" + label + "---");
this.sUpdate = new StreamSink<number>();
}
public run() {
this.sUpdate.listen(n => console.log("updated value", n));
this.sValidated.listen(n => console.log("VALIDATED VALUE", n));
this.sUpdate.send(0);
this.sUpdate.send(5);
this.sUpdate.send(11);
console.log("");
}
}
class TestViaFilter extends Test {
constructor() {
super("filter");
this.sValidated = this.sUpdate
.map(n => validate(n) ? n : null)
.filterNotNull();
this.run();
}
}
class TestViaGate extends Test {
constructor() {
super("gate");
const cGate = this.sUpdate
.map(n => validate(n))
.hold(false);
this.sValidated = this.sUpdate.gate(cGate);
this.run();
}
}
new TestViaFilter();
new TestViaGate();
Results:
---filter---
updated value 0
updated value 5
VALIDATED VALUE 5
updated value 11
---gate---
updated value 0
updated value 5
updated value 11
VALIDATED VALUE 11
In the first example, with filter, the updated value is correctly filtered. In the second example, with gate/hold, it is not (since it's using the previous, stale value)