Overloading can become extremely verbose very fast, because all arguments have to be repeated every time. However, often only the type hints on a few arguments change.
It would be nice to be able to abbreviate overloads by skipping arguments, and deferring their type hints. Consider this example from pandas-stubs
.
Series.reset_index type hint
@overload
def reset_index(
self,
level: Sequence[Level] = ...,
*,
drop: Literal[False] = ...,
name: Level = ...,
inplace: Literal[False] = ...,
allow_duplicates: bool = ...,
) -> DataFrame: ...
@overload
def reset_index(
self,
level: Sequence[Level] = ...,
*,
drop: Literal[True],
name: Level = ...,
inplace: Literal[False] = ...,
allow_duplicates: bool = ...,
) -> Series[S1]: ...
@overload
def reset_index(
self,
level: Sequence[Level] = ...,
*,
drop: bool = ...,
name: Level = ...,
inplace: Literal[True],
allow_duplicates: bool = ...,
) -> None: ...
@overload
def reset_index(
self,
level: Level | None = ...,
*,
drop: Literal[False] = ...,
name: Level = ...,
inplace: Literal[False] = ...,
allow_duplicates: bool = ...,
) -> DataFrame: ...
@overload
def reset_index(
self,
level: Level | None = ...,
*,
drop: Literal[True],
name: Level = ...,
inplace: Literal[False] = ...,
allow_duplicates: bool = ...,
) -> Series[S1]: ...
@overload
def reset_index(
self,
level: Level | None = ...,
*,
drop: bool = ...,
name: Level = ...,
inplace: Literal[True],
allow_duplicates: bool = ...,
) -> None: ...
The many overloads with many arguments make it hard to see at a glance what is going on. Compare this with the following, with some simplifications:
@overload
def reset_index(
...,
*,
inplace: Literal[True],
...,
) -> None: ...
@overload
def reset_index(
...,
*,
drop: Literal[True],
...,
) -> Series[S1]: ...
@overload
def reset_index(
...,
*,
drop: Literal[False],
...,
) -> DataFrame: ...
@overload
def reset_index(
self,
level: Sequence[Level] | Level | None = ...,
*,
drop: bool = ...,
name: Level = ...,
inplace: bool,
allow_duplicates: bool = ...,
) -> None | Series[S1] | DataFrame: ...
Which immediately makes it clear which arguments give which return. How this should work is when a ...
is encountered in an @overload
, then the type-hints of missing arguments are deferred to later overloads. Obviously this is just a very rough idea, but I wonder if other people feel the same.
Another benefit could be with refactoring. If an extra argument is added, we only have to modify the last overload instead of adding it to every existing overload.