One more potential issue. I dismissed it at first because I completely forgot that we also have syntax for calls with named parameters. If you have N optional parameters, the compiler would have to generate not N but 2^N - 1 extra functions. For example this function:
function g(
uint a? = 1, uint b? = 2, uint c? = 3, uint d? = 4, uint e? = 5,
uint f? = 6, uint g? = 7, uint h? = 8, uint i? = 9, uint j? = 10
) public {}
could potentially be called as f({e: 42}). To support every combination of omitted parameters the compiler would have to generate 1023 external functions even in this relatively simple case. Functions with more parameters would lead to serious bloat, even if you never actually use or need named arguments.
We can just limit it to only permutations that omit all parameters after a given position. It’s not a big issue if you only care about the savings because omitting parameters in the middle does not save you any calldata anyway and you can get some actual savings by just manually creating an overload. Still, this is a good example of why syntax-wise someone might prefer the mechanism with the default inserted by the caller - it does not have this limitation at all.