[phobos] is*Range + Qualified Types
David Simcha
dsimcha at gmail.com
Fri Sep 17 06:24:02 PDT 2010
On 9/17/2010 3:08 AM, Andrei Alexandrescu wrote:
> So the crux of the matter is not operating on constant ranges (which I
> believe we can safely drop), but obtaining non-constant ranges from
> constant containers.
I agree we need to drop operating on constant ranges for the general
case, but I think it's trivial to fix for a lot of common cases by just
adding Unqual. This would fix arrays, iota and everything else that has
a "natural" tail const.
>
> The idea that we could use a symbolic name for the qualifier is, I
> think, workable, but Walter has resisted it on account of exacerbated
> complexity in the implementation. We should explore other means for
> the time being.
>
> Right now a typical container implementation goes like this:
>
> struct Container(T)
> {
> ...
> struct Range { ... }
> Range opSlice() { ... }
> }
>
> A container might define several ranges, but c[] yields the
> container's primary, most prominent range. Now if we have a const
> Container!Widget object, we need to find an idiomatic way to extract a
> range from it. Here's some code that compiles and runs as expected:
>
> #!/bin/env rdmd
> import std.stdio;
>
> struct Container(T)
> {
> static struct Node { T payload; Node * next; }
> Node * root;
> struct Range(N) {
> private N * n;
> @property T front() { return n.payload; }
> @property bool empty() { return n is null; }
> void popFront() { n = n.next; }
> }
> Range!Node opSlice() {
> return typeof(return)(root);
> }
> Range!(const Node) opSlice() const {
> return typeof(return)(root);
> }
> }
>
> void main() {
> Container!int c1;
> c1.root = new c1.Node;
> c1.root.payload = 5;
> c1.root.next = new c1.Node;
> c1.root.next.payload = 7;
> foreach (i; c1[]) writeln(i);
>
> foo(c1);
> }
>
> void foo(const Container!int c1) {
> foreach (i; c1[]) writeln(i);
> }
>
> The basic idea is that the qualifier is propagated from the container
> to the range together with the type of the representation held inside
> the range.
This would solve the case where the range and the container are truly
distinct animals, but in a lot of cases they aren't.
>
> I'm not sure how generalizable this is, but it's a start. There is
> also the remaining nagging issue of duplicating the line
>
> return typeof(return)(root);
>
> which in other cases might expand to more lines.
Shouldn't inout solve this once it's fully implemented? Or maybe
template this parameters + auto return types?
Range!(inout Node) opSlice() inout {
return typeof(return)(root);
}
or
auto opSlice(this This)() {
return Range!(typeof(root))(root);
}
More information about the phobos
mailing list