Just about every language with iterators uses effectively syntactic sugar for them.
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
| for el in container {
//...
}
|
could translate to
| 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.