D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6756 - Idea about std.stdio.chunks and std.range.chunks
Summary: Idea about std.stdio.chunks and std.range.chunks
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-01 18:51 UTC by bearophile_hugs
Modified: 2015-03-23 13:05 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2011-10-01 18:51:32 UTC
I'm finding the recently introduced std.range.chunks quite useful. In Mathematica there is a similar function (but not lazy and even too much powerful) named Partition:

http://reference.wolfram.com/mathematica/ref/Partition.html

Unfortunately the one in Phobos often causes a name collision in my code:


import std.stdio, std.range;
void main() {
    auto ch = chunks(iota(15), 2);
    writeln(ch);
}


It gives:

test.d(3): Error: std.stdio.chunks at ...\dmd2\src\phobos\std\stdio.d(2038) conflicts with std.range.chunks(Source) at ...\dmd2\src\phobos\std\range.d(5261)


So you have to write:

import std.stdio, std.range;
void main() {
    auto ch = std.range.chunks(iota(15), 2);
    writeln(ch);
}



std.stdio.chunks is a struct with this constructor:

struct chunks {
    private File f;
    private size_t size;
    this(File f, size_t size) {
...



While std.range.chunks is a helper function:

Chunks!(Source) chunks(Source)(Source source, size_t chunkSize) {
    return typeof(return)(source, chunkSize);
}


That uses:

struct Chunks(Source) if(hasSlicing!Source && hasLength!Source) {
    this(Source source, size_t chunkSize) {
        this._source = source;
        this._chunkSize = chunkSize;
    }
...
}


I think you never call std.range.chunks with a File as first argument. The cause of the problem is probably shown in this little test:


struct Foo {}

void bar(Foo x) {}
void bar(T)(T x) if (!is(T == Foo)) {}
//void bar(T)(T x) if (is(T == Foo)) {}

void main() {
    bar([1, 2, 3]);
    bar(Foo());
}


test.d(4): Error: template test.bar(T) if (!is(T == Foo)) conflicts with function test.bar at test.d(3)


I don't know if in future DMD will allow overloading of functions with templates, but in the meantime a possible solution is to rename the std.stdio.chunks struct to a name that starts with upper case:


struct Chunks
{
    private File f;
    private size_t size;
    // private string fileName; // Currently, no use

    this(F f, size_t size)


To introduce a lowercase little helper function template with a template constraint that the first template argument must be a File:

    
Chunks chunks(F)(F f, size_t size) if (is(F == File))
{
    return Chunks(f, size);
}


(This doesn't cause a code bloat because std.stdio.range gets gets instantiated with only one type for the first argument, so it's like a single regular function.)


And then to add a negative template constraint to std.range.chunks:


Chunks!(Source) chunks(Source)(Source source, size_t chunkSize)
if (!is(Source == File) && hasSlicing!Source && hasLength!Source)
{
    return typeof(return)(source, chunkSize);
}


I think this solves the name collision problem.

By the way, do you know why std.range.Chunks has a template constraint while its helper function std.range.chunks doesn't have it? Most times you call std.range.chunks. So if you call it with wrong arguments you receive a template error inside std.range instead in your code. This is not good. So I think std.range.chunks needs the same template constraint as std.range.Chunks (plus !is(Source == File) at the start if you accept the idea shown here).
Comment 1 John Colvin 2015-03-23 13:05:08 UTC
There is no clash anymore, the example given works fine.