[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