One thing that bugs me sometimes with negative indexing is that 0 doesn't always wrap around the way I expect it to. This comes up when I'm trying to write code like (cut seq start (- (some-calculation))). Here's a hack that gives the behavior I expect:
(let old-cut cut
(def cut (seq start (o end len.seq))
(let length len.seq
(if (< start 0) (++ start length))
(if (< end start) (++ end length))
(unless (<= 0 start end length)
(err:+ "cut: The sign-adjusted indices were out of range or "
"backwards."))
(old-cut seq start end))))
;? (include "arctap.arc")
;?
;? (test-iso "cut should work for negative start and 0 end"
;? '(2 3 4)
;? (cut '(1 2 3 4) -3 -0))
;?
;? (test-iso "cut should work for positive start and 0 end"
;? '(2 3 4)
;? (cut '(1 2 3 4) 1 -0))
;?
;? (test-iso "cut should assume 0 start and 0 end are same position"
;? '()
;? (cut '(1 2 3 4) 0 -0))
(I haven't actually used arctap.arc yet, so I'm just parroting you in that section and hoping it helps.)
Unfortunately, if I have code that does something like (cut '(1 2 3 4) ref!start-trim (- ref!end-trim)), then this approach fails too (because of that double-zero assumption). In that case, I suppose I'd just resort to writing another function as a workaround.
(def cut-sides (seq front back)
(cut seq front (- len.seq back)))
I've searched through lots of the code I've written, and as it turns out, I haven't found one case where being having 0 as a "negative" index would have helped. :-p So while I still like it better my way, I don't have a real use case to show.
From another standpoint, maybe it's just that I don't want to rely on the behavior of something like (cut '(1 2 3 4) 3 1), where the indices are reversed. If I can exempt (cut '(1 2 3 4) -3 0) from that error/undefined zone (in a way that's smoothly consistent with cut's other behavior), then cut may be slightly more useful to me at some point. But yeah, I don't know exactly when it would pay off or whether some other behavior would be better.