www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - How to work with an "arbitrary input range"?

reply Adam D. Ruppe <destructionator gmail.com> writes:
I've seen the requirement tossed around a few times that functions should work
with arbitrary input ranges.

What, exactly, does this mean?

My first impression is:

void myFunction(T)(T t) if(isInputRange!(T)) {}

But I don't see how that actually works in practice. Suppose my function
parses some kind of text format, like D code or XML. It won't work with a
stream of integers.

OK, what about:

void myFunction(T)(T t) if(isSomeString!(T)) {}


The function could certainly work with that, but it doesn't seem to me to be
an arbitrary input range anymore; it is little different than if I just said
myFunction(string t).


Should it be something like this?

if(is(T.front : dchar))

(I'm sure that's actually wrong syntax, but hopefully you know what I mean)


That seems weak, since it wouldn't work with stdin.byLine, but perhaps it
shouldn't - the file format is char based, not line based. (should there be an
adapter range available there, to feed me one char at a time from a series of
lines? That seems to be adding a layer just to cancel out the one beneath it
though.)


Anyway, what's the right thing to do here?
Oct 21 2010
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Adam D. Ruppe <destructionator gmail.com> wrote:

[snip]
 Anyway, what's the right thing to do here?

I'd say: void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar ) ) {} -- Simen
Oct 21 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 21, 2010 16:56:48 Simen kjaeraas wrote:
 Adam D. Ruppe <destructionator gmail.com> wrote:
 
 [snip]
 
 Anyway, what's the right thing to do here?

I'd say: void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar ) ) {}

Though I'd suggest using Unqual!(ElementType!T). I'm not sure that it's necessary in this case (sinc ElementType!() is already cheating on string types), but I have found that if you want stuff to work with templates when dealing with const and/or immutable, you really need to watch out for places to use Unqual!(). - Jonathan M Davis
Oct 21 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar  
 ) )
 {}

Though I'd suggest using Unqual!(ElementType!T).

You're right, of course. -- Simen
Oct 21 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 21, 2010 15:32:45 Adam D. Ruppe wrote:
 I've seen the requirement tossed around a few times that functions should
 work with arbitrary input ranges.
 
 What, exactly, does this mean?
 
 My first impression is:
 
 void myFunction(T)(T t) if(isInputRange!(T)) {}
 
 But I don't see how that actually works in practice. Suppose my function
 parses some kind of text format, like D code or XML. It won't work with a
 stream of integers.

Well, then it doesn't make sense for your function to take an arbitrary input range. What you need is an arbitrary input range of characters (which may or may not be strings since it could be an Array or an SList or some other type of container entirely). What you need to check for, therefore, is that T is an input range with the correct element type (which is essentially what Simen suggests doing). - Jonathan M Davis
Oct 21 2010
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/21/10 17:32 CDT, Adam D. Ruppe wrote:
 I've seen the requirement tossed around a few times that functions should work
 with arbitrary input ranges.

 What, exactly, does this mean?

 My first impression is:

 void myFunction(T)(T t) if(isInputRange!(T)) {}

 But I don't see how that actually works in practice. Suppose my function
 parses some kind of text format, like D code or XML. It won't work with a
 stream of integers.

 OK, what about:

 void myFunction(T)(T t) if(isSomeString!(T)) {}


 The function could certainly work with that, but it doesn't seem to me to be
 an arbitrary input range anymore; it is little different than if I just said
 myFunction(string t).


 Should it be something like this?

 if(is(T.front : dchar))

 (I'm sure that's actually wrong syntax, but hopefully you know what I mean)


 That seems weak, since it wouldn't work with stdin.byLine, but perhaps it
 shouldn't - the file format is char based, not line based. (should there be an
 adapter range available there, to feed me one char at a time from a series of
 lines? That seems to be adding a layer just to cancel out the one beneath it
 though.)


 Anyway, what's the right thing to do here?

Good discussion. I think the algorithm is: 1. Figure out requirements on the range type (choose the weakest of input, forward, bidir, and random access) 2. Figure out requirements on the element type (choose the most general that works). Don't forget that you can access the element type of any range with ElementType!R. 3. Put the requirements in the template constraint. Example: // Process any range of characters void process1(R)(R r) if (isInputRange!R && isSomeChar!(ElementType!R)); // Process any range of built-in numbers void process2(R)(R r) if (isInputRange!R && is(ElementType!R : real)); // Process a random-acces range of ints void process3(R)(R r) if (isRandomAccessRange!R && is(Unqual!(ElementType!R) == int)); Andrei
Oct 21 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 21, 2010 17:13:32 Simen kjaeraas wrote:
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar
 ) )
 {}

Though I'd suggest using Unqual!(ElementType!T).

You're right, of course.

It can be quite baffling to have a template constraint start failing on you (particularly when it's several levels deep) just because you ended up using it with const. That's one of the reason that I specifically tested const and immutable versions of the various types in the datetime code that I have up for review. Without that, it's far too easy to miss things like a necessary Unqual! () and boom, your code doesn't work with const or immutable. Though I still haven't figured how to make SysTime immutable... (I think that it's because of the bug that makes postblit not work with const or immutable, but since the bug hasn't been fixed, I can't verify that...). - Jonathan M Davis
Oct 21 2010