[phobos] is*Range + Qualified Types

Steve Schveighoffer schveiguy at yahoo.com
Fri Sep 17 10:38:54 PDT 2010


That is one solution, but it still fails the implicit conversion test.  
Essentially, I should be able to convert a non-const range into a const range 
implicitly.

I'd also like to avoid a template solution if possible, since it seems like a 
hack to force you to template your range when you wouldn't normally need to.  
You also forgot about this awkwardness:

struct Range(N) {
   ...
   static if(!is(N == const))
   {
      @property void front(T newval) { n.payload = newval; }
   }
}


I don't have the answers however, tail const really is the best option, but I 
think there's a tail-const vein in Walter's forehead that throbs whenever he 
sees the words ;)

-Steve


----- Original Message ----
> From: Andrei Alexandrescu <andrei at erdani.com>
> To: Discuss the phobos library for D <phobos at puremagic.com>
> Sent: Fri, September 17, 2010 3:08:55 AM
> Subject: Re: [phobos] is*Range + Qualified Types
> 
> 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.
> 
> 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.
> 
> 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.
> 
> Any thoughts would be appreciated.
> 
> 
> Andrei
> 
> On  8/12/10 7:52 CDT, Steve Schveighoffer wrote:
> > ----- Original Message  ----
> > 
> >> From: Shin Fujishiro<rsinfu at gmail.com>
> >> 
> >>  David Simcha<dsimcha at gmail.com>   wrote:
> >>> I'm  looking to go on a major debugging spree and  make std.range work
> >>> with  const ranges.  For example,  the following should work:
> >>> 
> >>>   import  std.range, std.algorithm;
> >>> 
> >>> void main()  {
> >>>        const foo = map!"a ^^  2"([1,2,3,4,5]);
> >>>        auto myRetro =  retro(foo);
> >>> }
> >> 
> >> Could you elaborate   why?
> >> 
> >> Ranges with const elements must be common; but  what's the point  of
> >> const ranges?  Const random access  ranges are usable, but other  const
> >> ranges seem to be useless  since popFront and popBack can't be  const.
> > 
> > This seems to  point at a larger issue.
> > 
> > With the de-facto range T[], we get an  implicit cast to a range of const
> > elements, const(T)[].
> > 
> >  But we cannot get this with any user-defined type.  I think we will need  
to
> > address this eventually.  It's one of the main reasons  dcollections is not
> > const-aware, because I don't want to create several  types of ranges/cursors, 
>and
> > then all the duplicated functions that go  with it.  I'd rather use inout 
and
> > have it designate the return  type.
> > 
> > I think Janice proposed something a long long time ago  that allowed a 
>template
> > parameter to represent a const factor of a type,  a-la:
> > 
> > SList(V)
> > {
> >      struct  node
> >      {
> >         V  value;
> >         node *next;
> >       }
> >      node *head;
> > 
> >       struct range(const C)
> >      {
> >           C(node)* cur;
> >           @property C(V) front() {return cur.value;}
> >           void popFront() {next = cur.next;}
> >           @property bool empty() {return next !is null;}
> >       }
> > 
> >      range!(inout) opSlice() inout  {range!(inout) result;  result.cur = 
>head;
> > return result;}
> >  }
> > 
> > So basically, the way it works is C is substituted for a  const factor 
>(const,
> > immutable, or nothing).  And more importantly,  the compiler allows implicit
> > conversion from a range!(???) to a  range!(const).  Also, we can apply inout
> > rules.  (Note, I  don't know what to put as a const parameter for mutable, 
>since
> > that's  not a keyword, hence the ???).
> > 
> > Does this seem complex?   Yes.  But it's not as complex/hard to read/hard to
> > implement as 3  copies of all functions with 3 different range types.  It's 
>akin
> > to  the savings/clarity of inout.
> > 
> > What I'm unsure about is if we  need to do it this way.  I don't like using 
a
> > user-defined  parameter as the const factor, it makes it #1 hard to read, and 
>#2
> > every  person's const factor symbol may be different.  Most likely, you will  
>have
> > one const template parameter.  Do we need to support multiple  parameters?  
>inout
> > avoids requiring templates, because the code  generation is identical.  Can 
>we do
> > something similar to  inout?
> > 
> > We're going to need something like this to avoid  rediculous code repetition 
>for
> > any type that uses custom range  types.  Essentially what we need to 
>duplicate is
> > the "apply const  only to one member" feature of builtin arrays.
> > 
> > -Steve
> > 
> > 
> > 
> > 
> >  _______________________________________________
> > phobos mailing  list
> > phobos at puremagic.com
> >  http://lists.puremagic.com/mailman/listinfo/phobos
> _______________________________________________
> phobos  mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
> 


      


More information about the phobos mailing list