Simple; the Database.QueryLocator
implements the Iterable
interface, so actually you are always returning an Iterable of some form.
You can consider the ability to define your start
method as returning Database.QueryLocator
as using the covariant return type functionality of other object oriented languages. That the Salesforce documentation specifically shows two different signatures is just to help you understand that both options are available. Covariant return types are not supported across the Apex language, but rather in special cases like this.
It is worth noting that Apex is not a formally defined language and has some weirdnesses.
For example, it doesn't really support generics (templating) either. What you see is somewhat "smoke and mirrors". To illustrate this, you can define a batch class as implementing Database.Batchable<SObject>
yet the execute
method (when processing Account
records, for example) can receive List<Account>
and there will be no compilation or runtime error (as long as the start
method selects Account records).