If a foreach is encountered by the compiler
foreach (element; range) {
it's internally rewritten similar to the following:
for (auto it = range; !it.empty; it.popFront()) { auto element = it.front; ... }
Any object which fulfills the above interface is called an input range and is thus a type that can be iterated over:
struct InputRange {
@property bool empty();
@property T front();
void popFront();
}