On Wednesday, October 26, 2011 19:00:02 Steve Teale wrote: > On Wed, 26 Oct 2011 13:01:14 -0400, Jonathan M Davis wrote: > > Ranges are defined per templates in std.range. isForwardRange, > > isInputRange, isRandomAccessRange, etc. And it looks like isForwardRange > > specifically checks that the return type of save is the same type as the > > range itself. I was thinking that it didn't necessarily require that but > > that you'd have definite issues having save return a different type, > > because it's generally assumed that it's the same type and code will > > reflect that. However, it looks like it's actually required. > > But is it just required by std.range, or is it required at some > theoretical level by algorithms that can work with ranges as inputs and > outputs?
It complicates things to allow for the range returned by save not be the same type as the original range. It's probably possible to alter isForwardRange to allow save to return a different type, but I don't know what all of the side effects of such a decision would be. I'm certain however that it would break a fair bit of code. > > What you should probably do is have the result set be an object holding > > the data but not be a range itself and then overload opSlice to give you > > a range over that data (as would be done with a container). Then the > > range isn't in a position where it's trying to own the data, and it's > > clear to the programmer where the data is stored. > > But in my mind, just from a quick reading of the language definition, > slices are closely tied to arrays, which as you have already noted, are > not the best example of a range. > > Are ranges just a library artefact, or are they supported by the > language. They appear to be recognized by foreach, so if they are > recognized by D, then we should presumably have operator functions > opInputRange, opForwardRange, and so on, whatever those terms might mean. foreach supports the API of an input range: front, empty, and popFront. There's no need for overloaded operators of any kind. If you want to overload an operator for foreach, then use opApply. foreach is the _only_ place in the language that specfically supports ranges. Arrays are a poor example of ranges because they don't have an obviously associated container. A dynamic array is a range over a block of memory that the runtime maintains. With a full-blown container such as Array or RedBlackTree, it's the container that holds the data, and a range for one of them is a range over that container. People tend to think of arrays as being containers rather than just slices, so it becomes confusing to people. It's much easier to properly understand ranges if you think of them as being associated with a container like an iterator would be in C++. They don't normally own the elements that they're iterating over. When they do, you get situations such as input ranges where you can't save them (an input stream being a prime example). > If not, then facilities like std.algorithm should have a warning notice > like cigarettes that says "this facility may not be usable with POD". I'm afraid that I don't understand why a warning would be necessary. std.range lists the functions that each type of range must implement and it has templates for testing whether a particular type implements those functions for a given sort of range. I suspect that you're misunderstanding something fundamental about ranges. If you haven't read this article yet - http://www.informit.com/articles/printerfriendly.aspx?p=1407357 - I suggest that you do. It doesn't entirely match what std.range does (at least as far as naming goes) but it does explain the core concepts fairly well and as far as I know is the best explanation on ranges that currently exists. - Jonathan M Davis
