www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 6756] New: Idea about std.stdio.chunks and std.range.chunks

http://d.puremagic.com/issues/show_bug.cgi?id=6756

           Summary: Idea about std.stdio.chunks and std.range.chunks
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Phobos
        AssignedTo: nobody puremagic.com
        ReportedBy: bearophile_hugs eml.cc



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).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 01 2011