Bug 4464 – std.range.take does not always return Take!R
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-07-15T05:46:00Z
Last change time
2011-02-14T05:49:07Z
Assigned to
bugzilla
Creator
yebblies
Comments
Comment #0 by yebblies — 2010-07-15T05:46:13Z
When used with a range that supports slicing, take(r, n) returns r[0..n], which unfortunately makes it impossible to declare a variable of type Take!R and have it work in all situations.
I do consider this a bug and not an intended part of the design, please correct me if this is not the case.
eg.
int[] a;
Take!R r = take(a, 3); // type mismatch error
In most situations this is not a problem as type inference can be used, but when the type need to be known (as in a struct declaration) it won't work.
Because take is an auto function, typeof(take(r, n)) does not work either.
To fix this without disabling the slicing optimisation:
1. Change the template constraint on 'Take'
- struct Take(R) if (isInputRange!(R))
+ struct Take(R) if (isInputRange!(R) && !hasSlicing!R)
2. Add a template to handle the other case
+ template Take(R) if (isInputRange!R && hasSlicing!R)
+ {
+ alias typeof(R.init[0..R.init.length]) Take;
+ };
3. Change the return type of take from 'auto' to 'Take!R'
- auto take(R)(R input, size_t n) if (isInputRange!R && hasSlicing!R)
+ Take!R take(R)(R input, size_t n) if (isInputRange!R && hasSlicing!R)
With these changes take and Take work properly with everything.
I _will_ learn how to make real diffs one day.
Comment #1 by dsimcha — 2010-08-16T16:51:43Z
Fixed SVN.
Comment #2 by yebblies — 2010-12-15T22:12:30Z
Unfortunately this has been broken again by:
http://www.dsource.org/projects/phobos/changeset/2102
(http://d.puremagic.com/issues/show_bug.cgi?id=5052)
which added a new overload for 'take' but does not add a corresponding 'Take' template.
Patch:
Change the template constraint on the main Take range to match the main take function, and add a 'Take' template for the Take!Take!R case.
range.d:2074
- if(isInputRange!(Unqual!Range) &&
- (!hasSlicing!(Unqual!Range) || isNarrowString!(Unqual!Range)))
+ if((isInputRange!(Unqual!Range) && (!hasSlicing!(Unqual!Range) || isNarrowString!(Unqual!Range)))
+ && !is (Range T == Take!T))
+ // For the simplified Take!Take!R case
+
+ template Take(R)
+ if((isInputRange!(Unqual!R) && (!hasSlicing!(Unqual!R) || isNarrowString!(Unqual!R)))
+ && is (R T == Take!T))
+ {
+ alias R Take;
+ }
Comment #3 by bugzilla — 2010-12-16T01:24:12Z
Since I broke it, I'll take care of fixing it as well. (And I'll make sure to add a unittest so it doesn't break again.) But it'll probably have to wait until 2.051 is released.