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

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.