Splitter.opSlice(), ranges and const strings
Jonathan M Davis
jmdavisProg at gmx.com
Thu Feb 24 02:38:35 PST 2011
On Thursday 24 February 2011 01:53:33 spir wrote:
> On 02/24/2011 08:39 AM, Jonathan M Davis wrote:
> > On Wednesday 23 February 2011 22:41:53 Christopher Bergqvist wrote:
> >> Hi!
> >>
> >> I've run into an issue which I don't understand.
> >>
> >> Boiled down code:
> >> import std.regex;
> >>
> >> void main()
> >> {
> >>
> >> //string str = "sdf"; // works
> >> //const string str = "sdf"; // doesn't work
> >> immutable str = "sdf"; // doesn't work
> >> auto pat = regex(", *");
> >> auto split = splitter(str, pat);
> >>
> >> }
> >>
> >> Error:
> >> /Library/Compilers/dmd2/osx/bin/../../src/phobos/std/regex.d(3022):
> >> Error: this is not mutable
> >>
> >> Should splitter() be able to cope with const/immutable ranges?
> >>
> >> (That's with the latest official v2.052 dmd/phobos distribution for
> >> mac. I got the same error before upgrading from the v2.051
> >> also).
> >
> > Pretty much _nothing_ copes with const or immutable ranges. And if you
> > think about it, it generally makes sense. You can't pop the front off of
> > a const or immutable range. So, how could you possibly process it? The
> > are some cases where having tail const with ranges would work (assuming
> > that we could have tail const with ranges - which we currently can't),
> > but on the whole, const and immutable ranges don't really make sense.
> > They can hold const or immutable data, but a const or immutable range is
> > pretty useless on the whole.
>
> That's one question I'm wondering about for months (but always forget to
> ask): Why should /collection/ traversal shrink them? Why does the regular
> range stepping func (popFront) read, for arrays:
> this.data = thid.data[1..$];
> instead of:
> ++ this.cursor;
> ??? Should then be caled eg "stepFront", which imo is much better to
> express the semantics of traversal / iteration.
>
> I guess the issue expressed in this thread is /invented/ by the regular
> process of range, precisely by popFront. There is no reason to mutate a
> collection just to traverse it!
>
> And then, how do you traverse the collection again?
>
> unittest {
> auto a = [1,2,3];
> while (! a.empty()) {
> write(a.front() ,' ');
> a.popFront();
> }
> writeln();
>
> // below nothing written onto terminal
> while (! a.empty()) {
> write(a.front() ,' ');
> a.popFront();
> }
> writeln();
> }
??? Collection traversal _doesn't_ shrink them. Ranges get shrunken when you
iterate over them. That's how they work. They're a view into the
collection/container. They shrink. It's like car and cdr in lisp or head and
tail in haskell. Iterating over a range is very much like processing an slist
(as in the functional language type slist, not singly linked lists or the type
in std.container).
Now, arrays are a bit funny in that they're kind of both ranges and containers.
Now, as Steven pointed out in a recent thread, for a dynamically allocated
array, it's like the container is the GC heap, and an array is a range over a
portion of that heap. So, traversing an array as a range shrinks it but does not
affect its actual container - the GC heap. Static arrays, on the other hand,
really do own their memory and are actual containers - hence why you have to
slice them to pass to any range-based functions. And you have to slice any other
container type as well if you want to pass it to a range-based function.
So, iterating over a collection does _not_ shrink the collection. Iterating over
a _range_ does, but a range is a view into a container - a slice of it - so
you're just shrinking your view of it as you process it.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list