Skip to content

Conversation

@stroxler
Copy link
Contributor

@stroxler stroxler commented Dec 9, 2021

The draft of our Callable Type Syntax PEP is in a complete enough state that it is worth moving discussion to github so we have a history of major revisions going forward.

There are still many edits coming and we do not yet have a PEP number, hence keeping this as a draft PR.

Currently open problems (as of December 9) that I plan to get to soon:

  • inline references
  • add more to the motivation section
  • add more to the section comparing to other languages, and possibly touch on possible lambda syntax

Initial commit of a draft Callable Type Syntax PEP, ported
from a google doc at
https://docs.google.com/document/d/16UmBItZWIzKZK3ZTpDKH8vazNZ817E4UqKmPtebO4jQ/edit
@JelleZijlstra JelleZijlstra self-assigned this Dec 9, 2021
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little more sub-editing 🙂

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more things I spotted! Some of these are more elegance-of-writing points 🙂

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is my final pass 😄 it's a great PEP, I'm rooting for it!

stroxler and others added 5 commits December 9, 2021 20:51
This is based on Pradeep's feedback that we were getting to the
point too abruptly. The quality is probably lower than the rest
of the PEP because this new writing hasn't yet had any edits
or proofreading.

Also, since I was rewriting this section anyway I went ahead
and formatted it as 80 columns instead of infinite-width. The
whole file eventually needs to be reformatted but this one section
was blocking me (it was infinite width because it started as a
google doc, but using a text editor this is not so good)
I wrote a google doc describing this idea in more detail so that
anyone not familiar with it can get context without it taking
up over a page of the PEP itself.

We could potentially inline that entire discussion, but I think
having a separate doc is probably better because it might trigger
a discussion of proposing that idea that isn't directly relevant
to callable type syntax.

I also added some subsubsection headers to keep this subsection
organized.
@stroxler stroxler force-pushed the callable-type-syntax branch from 50975e4 to ba0b50f Compare December 11, 2021 16:56
@stroxler stroxler force-pushed the callable-type-syntax branch from ce8c821 to 0cdb7e0 Compare December 11, 2021 17:00
@stroxler stroxler force-pushed the callable-type-syntax branch from c6aea80 to 296c51f Compare December 14, 2021 03:05
@stroxler
Copy link
Contributor Author

I think I fixed most of the build issues.

It's unhappy with the header, and I'm lost - as far as I can tell, I pasted the formatting exactly from an existing pep, and checked it against a few others. But it complains about indentation and block quotes on almost every line, starting with my name.

@gvanrossum
Copy link
Member

Can you address Jelle's change request?

@stroxler
Copy link
Contributor Author

stroxler commented Dec 14, 2021

I think I addressed the comments already.

I'm not sure how to tell github about it though (and I accidentally requested re-review while I was trying to figure it out, which I didn't intend to do).

The docs say there's a way to "dismiss review" once you've addressed comments but I cannot see that option. Maybe I don't have the right permissions?

@JelleZijlstra
Copy link
Member

@gvanrossum do you want to do another round of review? If not I can merge the PR once CI is green and I can't find any more typos.

@stroxler I think you put the "in the" typo back at least once, let me check if it's still there.

@gvanrossum
Copy link
Member

IIRC you leave a comment saying

I have made the requested changes

@stroxler
Copy link
Contributor Author

I have made the requested changes

@gvanrossum
Copy link
Member

I dunno. I'll skim the thing one more time and then land it regardless.

@JelleZijlstra
Copy link
Member

(FYI, "I have made the requested changes" triggers the Bedevere bot on the CPython repo but it doesn't do anything on GiitHub in general.)

@stroxler
Copy link
Contributor Author

stroxler commented Dec 14, 2021

Awesome, thanks @JelleZijlstra and @gvanrossum!

If readability PRs later on are a problem then it may be worth waiting until @pradeep90 has another go at the Motivation section, it's new and I think we'll want to reword it.

But if that's not a problem I'd prefer to land and send to python-dev, I think the sections they'll care about should be ready once you've reread them.

@JelleZijlstra
Copy link
Member

Later PRs are fine, I'm happy to review them. Let's just land this before somebody else grabs our number. :)

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite various comments I'm going to land this, after fixing only one definite markup bug.

Comment on lines +421 to +423
The use of ``**P`` for supporting PEP 612 ``ParamSpec`` rules out any
future proposal using a bare ``**<some_type>`` to type
``kwargs``. This seems acceptable because:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Occasionally we hear from someone who has a TypedDict that they want to use as the type for some function's kwargs. If we wanted to support that for a function type's kwargs we'd be hosed -- the obvious notation would be (**TD) -> bool. Or maybe that would just work, and what you're ruling out here is use of (**int) -> bool to type e.g. def f(**args: int) -> bool: ...?

Copy link
Contributor

@pradeep90 pradeep90 Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... Technically, there is nothing to prevent us from supporting **KwargsTypedDict (or even **int) in the future. Type checkers could distinguish **KwargsTypedDict and **P based on the actual values of the variables.

The main reason we have **P instead of a bare P is to make it syntactically obvious that it is a ParamSpec (like Callable[P, R]). Otherwise, users might have trouble realizing that P is a ParamSpec in (Foo, P) -> int.

We could update the PEP (in a new PR) saying that it is actually forward-compatible with both **KwargsTypedDict and **int.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on the fence about this. Technically, there's nothing prevent us from using **<some_type> with divergent semantics depending on the information contained within <some_type>, type-checkers could handle this.

But it would be pretty unusual for python to let the semantics of the same syntax vary that much - a ParamSpec is a pretty different concept from typing the kwarg variadic argument.

My guess is that, in an extended syntax, we would work around this by requiring names for the vararg and kwarg,
so that we would use:

(**kwags: int) -> bool
(**kwargs: **MyTypedDict) -> bool

I think we should update the PEP to clarify that it's technically still possible to use **int and **MyTypedDict but I don't want to imply this is a good idea or say anything that's likely to prompt much discussion of it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, I don't see the issue with allowing **MyTypedDict in the future: just like **P, it means "this is the type for all of the kwargs". Perhaps to keep this option open we should avoid using the name "paramspec" in the AST and runtime objects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it would be pretty unusual for python to let the semantics of the same syntax vary that much

Would it, though? We have 1+2 == 3, vs "a" + "b" == "ab". We have a[i] (indexing list or tuple) vs. d[key] (lookup in dict or mapping) vs. list[int] (generic type). Etc. So I think there are enough precedents -- we don't need to worry about this looking odd.

community decides after more experience and discussion that we want
the additional features, they should be straightforward to propose
in the future.
- We realized that because of overloads, it is not possible to replace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "because of overloads" requires a complete example (e.g. an overloaded function, the observation that its type can't be expressed using current function types, and the conclusion that it must be done using a Callback Protocol). It might also be useful to explain why you can't just replace the overload with a union of function types. (Hm. Why couldn't you?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on a concrete example.

It might also be useful to explain why you can't just replace the overload with a union of function types. (Hm. Why couldn't you?)

Overloads correspond more to an intersection of callable types. If we had a union f: (int) -> str | ((list[int]) -> None), then we wouldn't be able to pass an argument to just one of the union items: f(42) would error because it's not a list[int]; f([1, 2]) would error because it's not an int.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- No replacement for callback protocol:

(Int, String) => Bool

Scala, like Python, has the ability to provide function arguments by name.
Funciton types can optionally include names, for example::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Funciton types can optionally include names, for example::
Function types can optionally include names, for example::

@gvanrossum gvanrossum merged commit 581d21d into python:main Dec 14, 2021
@gvanrossum
Copy link
Member

Congrats! I wish all PEP authors were like you. :-)

**Pradeep** `brought this proposal to python-dev
<https://mail.python.org/archives/list/[email protected]/thread/VBHJOS3LOXGVU6I4FABM6DKHH65GGCUB>`_
for feedback.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Usage Statistics section would be good to describe the methods, projects, and limitations. We could link to it from other parts of the PEP.

@stroxler stroxler deleted the callable-type-syntax branch December 14, 2021 17:21
@pradeep90
Copy link
Contributor

pradeep90 commented Dec 16, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants