Re: nuisance parameter names:
- In TypeScript there is a similar issue and they just live with it
- In C the type comes first and the arg name is optional; but the name is
often useful as documentation
So perhaps the nuisance parameter names aren't the worst compromise. When
you don't want to make up a name, you can write _ if there's only one
(surely common), or _1, _2, ... if there are multiple.
On Fri, Jun 11, 2021 at 9:17 AM Steven Troxler
I was planning to start a second thread about a more powerful syntax for Callable, but I think given concerns about forward-compatibility it makes sense to discuss here:
We’d like an easy way to express a callable using language features that the existing Callable type cannot describe: * optional arguments (with default values) * named and keyword-only arguments * variadic *args and *kwargs
The only general way to do this right now is via a protocol, as suggested in the mypy docs ( https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols): ``` from typing import Protocol, Iterable, List
class Combiner(Protocol): def __call__( self, *vals: bytes, maxlen: int | None = None ) -> List[bytes]: ...
def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: for item in data: ... ``` This has a bunch of disadvantages:
* It requires lots of boilerplate to import Protocol and build the dummy wrapper class * There’s an extraneous self in the __call__ signature that isn’t part of implementations * Using a Protocol (probably) isn’t obvious to folks who haven’t seen this suggestion already * The type isn’t first-class, we must define a Combiner alias because there’s no way to directly specify it
Pyre has a syntax (only used to display type errors) for general callable types. The type of a Combiner would be displayed as `Callable[[Args(vals, bytes), KeywordOnly(maxlen, int | None)`. This probably shouldn't be used for a PEP because
* it’s even more cumbersome than the Callable syntax we’re proposing improving above * it doesn’t clearly distinguish optional vs non-optional arguments
## A quick solution: function-as-a-type
A proposal from Łukasz is to allow functions to be used as types, which would allow us to rewrite the example above as
``` from typing import Iterable, List
def combiner(*vals: bytes, maxlen: int | None = None) -> List[bytes]: ...
def batch_proc(data: Iterable[bytes], cb_results: combiner) -> bytes: for item in data: ... ``` This has some awesome advantages:
* it’s a pure-typing change, the python interpreter would not need any updates * the syntax is familiar for anyone used to annotations already * in some situations a default function would already be available to use as a type
The main disadvantage is that the type still isn’t first-class: we can’t directly specify the type, instead we have to define a combiner function and refer to it in our annotations. Moreover, any positional-only arguments require dummy names that are irrelevant to the actual signature.
One thing we should be clear on is that accepting Łukasz's proposal does not at all prevent us from also working toward a first-class callable syntax that can express these things, so it might be well-worth making a PEP for just the function-as-a-type semantics.
## first-class callable syntax: Eric's proposal
Another option as proposed by Eric would be to use a stub-compatible syntax ``` ( _positional0: float, # required positional-only _positional1: float = ..., # optional positional-only /, a: bool, # required b: bool = ..., # optional *args: object, **kwargs: object, ) -> list[int] ``` This gives us a first-class callable type. My main concern is that the argument names for positional-only arguments are nuisance parameters. This creates two headaches: * when generating error messages, we'd probably have to auto-generate unique parameter names * This could be mildly annoying to implement and also mildly confusing for users * What I think is more important is that the nuisance parameters are likely to confuse users * I would guess that a minority of python devs are even aware of the `/` feature for positional args * Suddenly they'd have to use fake argnames and `/` for everything expressible using the existing Callable
## first-class callable syntax, no argnames for positional-only args
Another option would be to extend the syntax proposed above, for example something like ``` ( float, # required positional-only float = ..., # optional positional-only a: bool, # required b: bool = ..., # optional *args: object, **kwargs: object, ) -> list[int]
where general arguments are named and positional-only arguments have no name.
There would be no need to accept a / for positional-only arguments since they are indicated by lack of a name, but we would probably want to accept a bare * for keyword-only arguments: ``` ( int, # positional-only a: int, # normal * b: int, # required keyword-only c: int = ..., # optional keyword-only ) -> list[int] ```
This has an advantage in that the representation of a type is first-class and canonical because the nuisance argument names for positional-only arguments are eliminated. It also would be pretty compact for simple signatures, e.g. ``` (a: int, b: list[int]) -> list[int] ``` while scaling reasonably well over multiple lines for more complicated ones.
The disadvantage is that the syntax is slightly different from stub syntax. In my mind this is okay, because * Łukasz's proposal gives folks a stub-like alternative * stubs and types are not the same * a stub is an annotation of a concrete function with an implementation, so the arg names have a meaning * but in a type that abstracts implementations, the positional-only args don't have a name at all
The biggest reasons I'd prefer a no-name syntax are: * easy compatibility with the existing `Callable` type, which seems to me like a top priority * I suspect that in the long run teaching a new syntax will be less work than teaching that the argnames aren't part of the type _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...