On Tue, Mar 06, 2018 at 08:39:41AM -0700, Jonathan M Davis via Digitalmars-d-announce wrote: [...] > Yeah. If you're dealing with generic code rather than a specific range > type that you know is implicitly saved when copied, you have to use > save so often that it's painful, and almost no one does it. e.g. > > equal(lhs.save, rhs.save) > > or > > immutable result = range.save.startsWith(needle.save); > > How well Phobos has done with this has improved over time as more and > better testing has been added (testing for reference type ranges is > probably the most critical to finding this particular problem), but I > doubt that Phobos has it right everywhere, and I'm sure that the > average programmer's code has tons of these problems.
In my own code, I often run into subtle bugs that arise from ranges being unintentionally consumed because I forgot to call .save. So I tend to be extra careful about this. But yeah, it's so easy to miss unless your code actually uses ranges where it would make a difference. [...] > Ranges are wonderfully powerful, but they become a royal pain to get > right with truly generic code. And that's without getting into all of > the arguments about whether stuff like whether transitive fronts > should be allowed... I know we have disagreed on this before, but in my mind, it's very simple. Generic code should basically be written in such a way that it does the most making the least assumptions. Meaning, don't assume the return value of .front persists beyond the next .popFront, don't assume iterating the range won't consume it, etc.. It's just basic defensive programming. If the algorithm won't work without some of these assumptions, then make them explicit, either a part of the API, or clearly documented. IMNSHO, code that isn't written this way is just sloppy and a haven for hidden bugs. > Ranges are definitely one area where we could really use some redesign > to iron out some of the issues that we've found over time, but their > success makes them almost impossible to fix, because changing them > would break tons of code. But annoyingly, that's often what happens > when you implement a new idea. You simply don't have enough knowledge > about it ahead of time to avoid mistakes; those are easy enough to > make when you really know what you're doing, let alone with something > new. [...] Andrei has said before, and probably on more than one occasion, that if he were to redesign ranges today, one of the things he would do differently was to change the definition of forward range so that .save is basically implicit on copying the range object, and non-forward input ranges would just be reference / non-copyable types. But that boat has long sailed, and we just have to make do with what we have today. Changing this now will literally break just about *every* D program that uses ranges, which is breakage of an ecosystem-killing magnitude that I can't even contemplate. I would much rather go with a less intrusive breakage like killing autodecoding with fire, than with something that will basically require me to rewrite practically every D program I ever wrote. T -- "You know, maybe we don't *need* enemies." "Yeah, best friends are about all I can take." -- Calvin & Hobbes