Java and C# uses the Iterable interface; C++ uses duck-typing with begin(), end() member functions and a few operator overloads on the iterator object; D also does duck-typing but you need to explicitly give the foreach construct the range object (usually with the opRange operator overload).
With function overloading you can do much of the same
1 2 3 | for el in container { //... } |
could translate to
1 2 3 4 | for it:= iterator(container); finished(it); advance(it) { el := element(it); //... } |
Then it's up to the use code to follow the contracts.
But I don't really like duck-typing because that you rely on overloads not necessarily local to each other. I'll get into that further in another topic.