04:36
<Justin Ridgewell>
I've been thinking about this, and there's a lot of caveats to doing flattening on-demand.
04:37
<Justin Ridgewell>
You can't really do it during .get() or .run(), because there's a possibility that a snapshot has already been taken of the context that can still observe the shadowed Var value.
04:38
<Justin Ridgewell>
And, worse, there's a future snapshot after the current .get() or .run() which could observe it.
04:38
<Justin Ridgewell>
The only time you can flatten is when there is no active context, eg, as part of GC passes
05:14
<Justin Ridgewell>
It shouldn't be too much to implement: https://gist.github.com/jridgewell/ef8a674291f8f7419a2bea0448c3b0eb
06:23
<Andreu Botella>
You can't really do it during .get() or .run(), because there's a possibility that a snapshot has already been taken of the context that can still observe the shadowed Var value.
I think that's only the case on your implementation that mutates in-place. Purely persistent implementations don't have that issue
06:27
<Justin Ridgewell>
That would only solve already existing chains, it wouldn’t solve future snapshots of the current chain
06:28
<Justin Ridgewell>
At least during an active run, you could (but why) do it during get inside an empty chain
06:29
<Justin Ridgewell>
Or you push it into snapshot restore, which it the most performance critical
06:42
<Andreu Botella>
I'm having trouble conceptualizing this, but I haven't had my coffee yet
06:43
<Andreu Botella>
the way I was thinking of it was that, you could just replace the current snapshot from a linked list to a map, without mutating anything else
06:43
<Andreu Botella>
you could even mutate the current entry in the linked list by making it store a map and make its next pointer be null
06:46
<Andreu Botella>
if you imagine a linked list representation of a map, where each entry in the list is an update on the map represented by the rest of the linked list, flattening an entry into a map would not change the semantics, for that entry as the snapshot, or for anything that has that entry as part of the list
06:47
<Andreu Botella>
now, flattening on get is probably not a good idea because of the performance considerations – even amortized, there is an implementation of flattening on run that has the same asymptotic runtime on get, if not better
06:49
<Andreu Botella>
I'm working on a doc comparing various possible implementations
06:58
<Justin Ridgewell>

My concern is with:

a.run(1, () => {
  b.run('b', () => {
    a.run(2, () => {
      // flatten here
      a.get();
    })

    // Still observe 1 here
    a.get();
  })
});
06:58
<Justin Ridgewell>
If we flatten inside the a.run(2, …), we can still observe the 1 value afterwards
07:00
<Justin Ridgewell>
So either the chain still exists fully after run() ends (in which case, every first .get() is in a run is expensive?), or we've mutated the previous context and lost the value
07:00
<Justin Ridgewell>
It just doesn't seem efficient to do on demand
07:01
<Justin Ridgewell>
And we don't really free any memory compared to the map approach
07:01
<Justin Ridgewell>
If we do the flatten during GC, we can at least maximize savings from all chains at once