Overhauling the notion of output range

Christian Kamm kamm-incasoftware at removethis.de
Mon Jul 12 11:55:31 PDT 2010


Andrei Alexandrescu wrote:
> Yes. The point is that with a delegate you must choose between accepting
> E and E[]. Given the constraint, it's better for everyone to accept E[]
> and let put() take care of the occasional E by doing the wraparoo
> (&elem)[0..1].

I don't think the current implementation of put allows passing E and E[] 
correctly:

void put(R, E)(ref R r, E e) if (isOutputRange!(R, E)) 
{
  if (isArray!E &&  is(typeof(r(e))))
  {
    r(e);
  }
  else static if (is(typeof(r(new E[]))))
  {
    r((&e)[0 .. 1]);
  }
  else
  {
     static assert(false);
  }
}

Example: typeof(fn) == void function(int[][]).
put(fn, int[]) -> ok
put(fn, int[][]) -> no match, isOutputRange!(fn, int[][]) fails.

You'll need a
void put(R, E)(ref R r, E[] a) if (isOutputRange!(R, E))
overload get the desired behavior.

Implementing that one generically also makes explicit what Steve was saying: 
front-assignable ranges and classic output ranges are stuck using put with a 
single element in a loop. Associating different performance tradeoffs with 
abstractions that should be interchangeable sounds odd.

In the end it comes down to the question why R.put(E) and void R(E[]) should 
both be output ranges for E. They should either take E or E[]. 

I'd go with void foo(E) being an output range for E and define the overloads
void put(ref R r, T t) if (isOutputRange!(R, T[])) // makes 1-element slice
void put(ref R r, E e) if (isOutputRange!(R, E))
void put(ref R r, A[] a) if (isOutputRange!(R, A)) // uses foreach

Christian



More information about the Digitalmars-d mailing list