zipper icon indicating copy to clipboard operation
zipper copied to clipboard

Mark parent info as modified when moving up in zipper

Open Overbryd opened this issue 2 months ago • 0 comments

  • Added is_modified flag set to true in parent info during up/1 operation.
  • Added test zipper_up_modified/1 to verify the modified flag propagation on zipper manipulations.

I have encountered an issue when modifying a node in a tree, and then moving along the tree. zipper:up does not retain the modified status for traversal to parent nodes, and therefore traversing upwards (like done in zipper:next_recur) looses the modified node.

The example test case zipper_up_modified should demonstrate the issue. Here is a graphical representation:

planet "earth"
\_ continent "America"
  |_ country "Argentina"
  \_ country "Brasil"

Moving the tree to country "Brasil" and changing it to country "Peru" causes the following issue:

1. Replacing the node country "Brasil" with country "Peru" sets is_modified to true
2. Traversing upwards replaces the children of continent "America" correctly. But is_modified is not retained.
3. Traversing upwards again, takes the children of planet "Earth" and therefore looses the updated children of content "America"

With the fix, the behavior is correct:

1. Replacing the node country "Brasil" with country "Peru" sets is_modified to true
2. Traversing upwards replaces the children of continent "America" correctly. Now the node content "America" sets is_modified to true
3. Traversing upwards again, replaces the children of planet "Earth" and therefore retains the updated children of content "America"

=> correct tree state

When modifying country "Brasil" to, for example, country "Peru" the info => #{ is_modified => true } is set on the node. The issue is, that is_modified is not propagated when moving upwards with zipper:up. This causes issues with the state of the tree being lost in traversal, due to the children of parents being replaced with their previous versions.

Therefore I changed zipper:up to mark the whole lineage with info => #{ is_modified => true }. This makes upwards traversal retain the proper state of the tree, even when traversing further upwards.

Overbryd avatar Oct 28 '25 14:10 Overbryd