I agree that nuisance parameter names offer a good compromise. It's better IMO than creating an inconsistent syntax with subtly different rules in different contexts. Steven mentioned that pyre uses a special syntax for Callable types that appear in diagnostic messages. Pyright also uses a special syntax in its diagnostic messages. It happens to be consistent with my proposal above. :) You can see this if you run pyright on the following code. ```python from typing import Callable, ParamSpec, Protocol, TypeVar class Callback1(Protocol): def __call__(self, x: int, /, y: str, *, z: int = ...) -> None: ... _P = ParamSpec("_P") _T = TypeVar("_T") def get_sig(x: Callable[_P, _T]) -> Callable[_P, _T]: """ Converts a callable protocol instance into its callable signature """ ... def func(x: Callable[[int, str], None], y: Callback1): reveal_type(x) # "(_p0: int, _p1: str) -> None" reveal_type(get_sig(y)) # "(x: int, /, y: str, *, z: int = ...) -> None" ``` Note that parameter names (e.g. `_p0` and `_p1) are synthesized when they are not known. I agree that most Python users are not aware of `/`, so that could be an issue with adoption. The distinction between positional-only and position-or-keyword parameters is significant, so one could argue that it's important to educate Python programmers about this distinction. However, if we decide that `/` is too ugly or onerous to include, we could support the pre-PEP-570 convention of naming position-only parameters with double underscores (`__p0`, etc.). ``` C1 = (__p0: int, __p1: int) -> int # Equivalent to Callable[[int, int], int] ``` Alternatively, we could support the name `_` for all parameters that are position-only and suspend the normal semantic rule that parameters names need to be unique within a signature. I kind of like this option because it's readable, concise, and still follows the standard syntax rules for `def`. ``` C1 = (_: int, _: int) -> int # Equivalent to Callable[[int, int], int] ``` -Eric