Wanted to chime in on the leading underscores workaround –
I think this makes sense as a shorthand if we’re forced to provide a name, but the ‘_’ symbol to me is still associated with “unused” rather than “positional” argument, and that this isn’t intuitive unless someone has read the rules in
the PEP and knows this is something they need to add to every callable type.
This is a good point: sometimes you really *do* have a parameter position that is unused (needed for historical reasons / compatibility).
I’m also worried about the extra verbosity when many callables may not need to deal with or think about named parameters at all.
Yeah, this is the main reason why we need to keep looking.
I’d be supportive of the shorthand where `(int, str) -> float` is still acceptable if we do not have named params.
Yeah, I think this is a reasonable compromise, even if it means that there's a discrepancy: it would mean that
def foo(bar, baz) -> int: ...
does not correspond to the signature
foo: (bar, baz) -> int
instead it corresponds roughly to
foo: (Any, Any) -> int
But really the latter would be a precise match for
def foo(bar, baz, /) -> int: ...
Additionally, what are the concerns with allowing a hybrid of named and unnamed params, ie.:
f: (int, str, *, foo: int = ..., **kwargs: str) -> bool
If we were to allow this, it'd be harder to give a simple rule for when the argument names can be omitted or not -- for example would we allow this?
f: (int, name: str) -> bool
or this?
f: (count: int, str) -> bool
or even this?
f: (a: int, b, c: str) -> bool
--