Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zipper end state behaves differently for skip vs raw movement #155

Open
lread opened this issue May 10, 2021 · 1 comment
Open

Zipper end state behaves differently for skip vs raw movement #155

lread opened this issue May 10, 2021 · 1 comment
Labels
hammock requires some thought

Comments

@lread
Copy link
Collaborator

lread commented May 10, 2021

Not sure if this is a bug or a behavior to document, just recording some notes for now.

Version
Pre-existing in v0

Platform
All

Behaviour
Let's explore what happens with next (whitespace aware) vs next* (raw) in rewrite-clj.
These tests were carried out on v0.6.1 just to make sure this behaviour was not something v1 code introduced.

-- Variation 1 next on underlying clojure.zip zipper
stays on the last node when end is hit, zipper is still traversable:

(require '[clojure.zip :as z])

(->> "[1 2 3]"
     z/of-string
     (iterate z/next)
     (take 10)
     (map (juxt z/string z/end?)))
;; => (["[1 2 3]" nil]
;;     ["1" nil]
;;     ["2" nil]
;;     ["3" nil]
;;     ["3" true]
;;     ["3" true]
;;     ["3" true]
;;     ["3" true]
;;     ["3" true]
;;     ["3" true])

(->> "[1 2 3]"
     z/of-string
     (iterate z/next)
     (take 10)
     last
     z/prev
     z/string)
;; => "2"

-- Variation 2 next* on underlying clojure.zip zipper
hits an end state, node becomes root node, zipper is no longer traversable:

(->> "[1 2 3]"
     z/of-string
     (iterate z/next*)
     (take 10)
     (map (juxt z/string z/end?)))
;; => (["[1 2 3]" nil]
;;     ["1" nil]
;;     [" " nil]
;;     ["2" nil]
;;     [" " nil]
;;     ["3" nil]
;;     ["[1 2 3]" true]
;;     ["[1 2 3]" true]
;;     ["[1 2 3]" true]
;;     ["[1 2 3]" true]

-- Variation 3 next on underlying "custom zipper"
rewrite-clj's zipper that supports position tracking, behaviour is same as next on underlying clojure.zip zipper.

(->> (z/of-string "[1 2 3]" {:track-position? true})
     (iterate z/next)
     (take 10)
     (map (juxt z/string z/position z/end?)))
;; => (["[1 2 3]" [1 1] nil]
;;     ["1" [1 2] nil]
;;     ["2" [1 4] nil]
;;     ["3" [1 6] nil]
;;     ["3" [1 6] true]
;;     ["3" [1 6] true]
;;     ["3" [1 6] true]
;;     ["3" [1 6] true]
;;     ["3" [1 6] true]
;;     ["3" [1 6] true])

(->> (z/of-string "[1 2 3]" {:track-position? true})
     (iterate z/next)
     (take 10)
     last
     z/prev
     ((juxt z/string z/position)))
;; => ["2" [1 4]]

-- Variation 4 next* on underlying position tracking zipper
behaviour is same as next* on underlying clojure.zip zipper, we end up at root node and zipper is no longer traversable:

(->> (z/of-string "[1 2 3]" {:track-position? true})
     (iterate z/next*)
     (take 10)
     (map (juxt z/string z/position z/end?)))
;; => (["[1 2 3]" [1 1] nil]
;;     ["1" [1 2] nil]
;;     [" " [1 3] nil]
;;     ["2" [1 4] nil]
;;     [" " [1 5] nil]
;;     ["3" [1 6] nil]
;;     ["[1 2 3]" [1 1] true]
;;     ["[1 2 3]" [1 1] true]
;;     ["[1 2 3]" [1 1] true]
;;     ["[1 2 3]" [1 1] true])

So at least we are consistent for next* and next for custom and clojure zipper.

-- Variation 5 - Sanity check on clojure.zip zipper
And just a quick check on using a clojure.zip zipper outside of rewrite-clj (yeah, same behaviour as next* in rewrite-clj):

(require '[clojure.zip :as czip]

(->> '[1 2 3]
     czip/vector-zip
     (iterate czip/next)
     (take 10)
     (map (juxt czip/node czip/end?)))
;; => ([[1 2 3] false]
;;     [1 false]
;;     [2 false]
;;     [3 false]
;;     [[1 2 3] true]
;;     [[1 2 3] true]
;;     [[1 2 3] true]
;;     [[1 2 3] true]
;;     [[1 2 3] true]
;;     [[1 2 3] true])

(->> '[1 2 3]
     czip/vector-zip
     (iterate czip/next)
     (take 10)
     last
     ;; we are at root can we navigate down?
     czip/down)
;; => Execution error (NullPointerException) at fiddle/eval10795 (REPL:514).
;;    null
@lread lread added the hammock requires some thought label May 10, 2021
@lread lread changed the title End behaves differently for skip vs raw movement Zipper end state behaves differently for skip vs raw movement May 10, 2021
@lread
Copy link
Collaborator Author

lread commented May 12, 2021

Current perceived impact:

Zipper end state is confusing:

  • for skip movement, end is past last node but we stay on last node, zipper is still usable
  • for raw movement, end is past last node, we state in this state, zipper is no longer usable

@lread lread added this to rewrite-clj Jul 3, 2024
@lread lread moved this to Medium Priority in rewrite-clj Jul 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hammock requires some thought
Projects
Status: Medium Priority
Development

No branches or pull requests

1 participant