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.