Why foreach(c; someString) must yield dchar

dsimcha dsimcha at yahoo.com
Wed Aug 18 19:37:04 PDT 2010


I've been hacking in Phobos and parallelfuture and I've come to the conclusion
that having typeof(c) in the expression foreach(c; string.init) not be a dchar
is simply ridiculous.  I don't care how much existing code gets broken, this
needs to be fixed.  Otherwise, all generic code will have to deal with it as a
special case.  Most of it will probably overlook this special case in
practice, and the net result will be more broken code than if we just bite the
bullet and fix this now.  Here are some examples of the absurdities created by
the current situation:

static assert(is(typeof({
    foreach(elem; T.init) {
        return elem;
    }
    assert(0);
}) == ElementType!(T));

Looks reasonable.  FAILS on narrow strings.

size_t walkLength1(R)(R input) {
    size_t ret = 0;
    foreach(elem; input) {
        ret++;
    }

    return ret;
}

size_t walkLength2(R)(R input) {
    size_t ret = 0;
    while(!input.empty) {
       ret++;
       input.popFront();
    }

    return ret;
}

assert(walkLength1(stuff) == walkLength2(stuff));

FAILS if stuff is a narrow string with characters that aren't a single code point.

void printRange(R)(R range) {
    foreach(elem; range) {
        write(elem, ' ');
    }
    writeln();
}

Prints garbage if range is a string with characters that aren't a single code
point.

auto rangeMax(R)(R range) {
    enforce(!range.empty);

    auto ret = range.front;
    foreach(elem; range) {
        if(elem > ret) {
            ret = elem;
        }
    }

    return ret;
}

This will not find the largest character in the range if R is a narrow string.

If D is at all serious about generic programming, we simply can't require this
to be dealt with **everywhere** as a special case.


More information about the Digitalmars-d mailing list