tl;dr: Go's "range" operator has eliminated the most common trap where I make off-by-one errors. The next largest category of off-by-one errors would be eliminated if there was a way to specify the last item in an array. It would also improve a developer's ability to convey intent.
... I've been coding for a few years (first line of BASIC was in September 1979) and I have to admit that off-by-one errors have always been a problem for me. I guess I'm just that kind of sloppy. Speaking for myself, the biggest category of potential off-by-one errors is when constructing "for" loops. Go's "range" operator eliminates that entire category of potential mistakes. For that I'm thankful. So what is my next largest category? Again, speaking only for myself, it is the fact that the last item in an array is len(a)-1. It's easy to remember to subtract 1, but when it's buried in the middle of a formula, it's non-obvious and obscured. More importantly, it hides intent. For example often the -1 is cancelled out by a +1 elsewhere in the formula. Now that was originally len(a)-1-+1-y becomes len(a)-y. Original intent obscured. Or worse, a formula like len(a)-1-y becomes len(a)-z because someone noticed that z==y-1 and made the substitution. Yes, it is a premature optimization but I bet you’ve done a similar substitution many times. Oh wait. Did you notice the typo in the previous paragraph? The substitution would be valid if z==y+1, not z==y-1. The fact that you didn’t notice proves my point. Now do you understand my pain? Luckily I have a simple proposal that would fix this. What if there was a built in function highest() that was like len(), but returns the highest valid index. Sure, it is nothing more than a substitute for len(a)-1. Not a super huge difference, but I think it would eliminate this class of off-by-one errors. My example from before becomes: OLD: len(a)-1-+1-y NEW: highest(a)+1-y` The second example loses the temptation for premature optimization: OLD: len(a)-1-y NEW: highest(a)-y Example: The classic Go “Pop from a stack” idiom is improved: OLD: x, a = a[len(a)-1], a[:len(a)-1] NEW: x, a = a[highest(a)], a[:len(a)-1] Note: Intention is clearer: x is the last element, a has a reduction in the length by 1. NEW2: x, a = a[highest(a)], a[:highest(a)] In this case the intention is even more clear: “x is the last element, a is all but the last element.” Loop through elements in reverse order: OLD: for i := len(s)-1; i >= 0; i-- { NEW: for i := highest(s); i >= 0; i-- { Note: The intention is much clearer. I realize that the go project is very reluctant to add new features and rightfully so. That said, I think highest() (or maybe end(), ultimate()? final(), hind()?) would be a great human-centric feature to add. Tom WIth better formatting... https://www.yesthatblog.com/post/0068-go-off-by-one -- Email: t...@whatexit.org Work: tlimonce...@stackoverflow.com Twitter: YesThatTom Blog: https://www.yesthatblog.com -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAHVFxgmi3WLfiEsTyiXPtXHs57_o_n86C-e-nHpgXgG8y%2BKYDA%40mail.gmail.com.