digitalmars.D - How to work with an "arbitrary input range"?
- Adam D. Ruppe (22/22) Oct 21 2010 I've seen the requirement tossed around a few times that functions shoul...
- Simen kjaeraas (7/8) Oct 21 2010 I'd say:
- Jonathan M Davis (7/17) Oct 21 2010 Though I'd suggest using Unqual!(ElementType!T). I'm not sure that it's
- Simen kjaeraas (4/8) Oct 21 2010 You're right, of course.
- Jonathan M Davis (11/19) Oct 21 2010 It can be quite baffling to have a template constraint start failing on ...
- Jonathan M Davis (8/20) Oct 21 2010 Well, then it doesn't make sense for your function to take an arbitrary ...
- Andrei Alexandrescu (17/39) Oct 21 2010 Good discussion. I think the algorithm is:
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
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
On Thursday, October 21, 2010 16:56:48 Simen kjaeraas wrote:Adam D. Ruppe <destructionator gmail.com> wrote: [snip]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 DavisAnyway, what's the right thing to do here?I'd say: void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar ) ) {}
Oct 21 2010
Jonathan M Davis <jmdavisProg gmx.com> wrote:You're right, of course. -- Simenvoid fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar ) ) {}Though I'd suggest using Unqual!(ElementType!T).
Oct 21 2010
On Thursday, October 21, 2010 17:13:32 Simen kjaeraas wrote:Jonathan M Davis <jmdavisProg gmx.com> wrote: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 DavisYou're right, of course.void fun( T )( T t ) if ( isInputRange!T && is( ElementType!T == dchar ) ) {}Though I'd suggest using Unqual!(ElementType!T).
Oct 21 2010
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
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