regular table insertion in nudl is performed with `then T args...`.

the language guarantees that all insertions on T are complete before all queries on T for one iteration.

to support cyclical changes, one can `cue T args...`. this is implemented by requiring tables to buffer these changes until the end of the iteration, where they are then committed as if performed in the next iteration.

but keeping this temporary store is inefficient, and possibly unnecessary.

#devlog #nudl

however, if a cue is the only change that a trigger performs (and we could enforce this), and all of such triggers have no direct dependencies on each other (which we could also enforce), then all cue-triggers can be scheduled to happen at the end of the iteration.

it does force the program to utilize double buffering in some cases (e.g. (a) must be transformed to (b)), but significantly reduces implementation effort and memory/performance overhead.

#devlog #nudl

the scheduler can be made to behave by inserting implicit edges from all triggers that directly depend on our trigger's cue target, to our cue target.

then case (a) causes a strong cycle, but case (b) doesn't, and also enforces correct topological order, running the top triggers first.

okay. i feel confident enough to implement this.

#devlog #nudl

first example properly executes and runs with the perf improved cue. it *is* slightly more annoying, but only when you alter tables while you are reading them.

on the upside, the structure is more efficient and computationally reasonable, and optimally prepared for parallelization (though not in this very serial implementation of a fibonacci number generator.)

#devlog #nudl

here is for instance how the implementation of the option table type has improved by this change:

before: https://paste.sr.ht/~duangle/3d3931dbd491f24d279d0bcb63e2f9318c9105f4

after: https://paste.sr.ht/~duangle/cf1ed519a84adc1135a65f280e40196be357af88

#devlog #nudl

after this change it became clear that this new deferred insertion pattern benefits greatly from a new table type, the delta table, which clears itself on each iteration, and effectively batches operations.

#devlog #nudl

@lritter isn't that implementation, rather than user visible type?
@StompyRobot how so?
@lritter i don't care whether a table uses write-ahead batch optimization or not. As long as the semantic is the same (with query look-aside)

@StompyRobot that is what i removed.

tables no longer need to implement their own implicit batching.

instead, the scheduler positions cues so that they become regular insertions.

but the user now needs to figure out how they prevent read/writes in the same rule, since this is not threadsafe, and the compiler will complain about a cycle.

hence, the delta (now named "queue") table type which is optimal for temporary storage.

@StompyRobot when you have a situation with at least two rules, one reads A and inserts into B, one reads B and cues to A, then no queue is required.
@StompyRobot does that make a bit more sense?
@lritter I see, so it's actually a semantic change, for performance (locking cost) reasons. That clears that up!