Update: Work on Optional Syntax PEP

Hi there, Recently I have been working on an implementation for PEP 604 (https://www.python.org/dev/peps/pep-0604/). While working on this, I started reviewing and exploring what new Optional syntax would look like in the Python language. I've written a rough draft of a PEP and wanted to present it to this email list before submitting a PR. I know this is a topic that has been discussed in many settings (Github issues, in person typing meetups, etc. )previously, and wanted to solicit feedback here first. Let me know if submitting a PR would be a better way to gauge sentiment and feedback on this proposal. Draft Proposal (branch compare): https://github.com/python/peps/compare/master...MaggieMoss:optional-syntax-p... Gist: https://gist.github.com/MaggieMoss/c848cb3a581979f445d075c15629c950 Thanks again, Maggie

Wow, you've been busy! (I know I still owe you a review on the PEP 604 implementation. It's on my TODO list. :-) My main observation at this point is that introducing a new token means that there is no way to use this in code that has to be backwards compatible with Python 3.9 and before (assuming you could get it into 3.10). This is different for PEP 604's `|` operator, which can be used in Python 3.7+ as long as the `from __future__ import annotations` magic import is used to avoid runtime errors on things like `int | str`. The `|` operator could also be used in typeshed, since it is valid Python 3.7 syntax. (While I don't know of any type checkers that currently support it yet, supporting it would not require changes to the Python *parser* -- at least typed_ast can handle it without changes.) However, this shouldn't be a big strike against the proposal. In a few short years Python 3.10 will be the oldest version supported and all will be well. Another concern I have is that we already have two ways to spell "optional": `Optional[T]` and `T | None`. Finally, IMO the argument against `Optional[T]` is stronger than the argument against `T | None`. (But your point that 7% of annotations use Optional is well taken.) --Guido On Thu, Sep 3, 2020 at 12:04 PM None via Typing-sig <typing-sig@python.org> wrote:
-- --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...>

Nice. This ? makes sense to me, especially given the similar use in many other languages. Though I wonder how to represent `Union[bytes, str]?` using the | syntax. `(bytes | str)?` or `bytes? | str?`. That should be covered. I believe Thomas Wouters (cc'd) has been mulling over ? as a token for a non conflicting non-typing purpose. Maybe this is the decade of the ?. I'm not worried about being unable to use a new feature on older versions of the language. That is normal, there is always a long time frame before a syntax feature can see wide adoption. (ex: yield, with, set literals, 1_000, async, ...) -gps On Thu, Sep 3, 2020, 3:19 PM Guido van Rossum <guido@python.org> wrote:

Though I wonder how to represent `Union[bytes, str]?` using the | syntax. `(bytes | str)?` or `bytes? | str?`
Good question! From the theoretical point of view, all your examples should be equal. Since Union always maintains its structure. Currently, it works correctly: ``` from typing import Optional, Union x: Optional[Union[int, str]] y: Union[Optional[int], Optional[str]] reveal_type(x) # Union[builtins.int, builtins.str, None] reveal_type(y) # Union[builtins.int, None, builtins.str, None] ``` However, mypy can possibly flatten repeating `None` values, but that's another topic. пт, 4 сент. 2020 г. в 01:48, Gregory P. Smith <greg@krypto.org>:

On Fri, Sep 4, 2020 at 12:14 AM Никита Соболев <n.a.sobolev@gmail.com> wrote:
I know they are equivalent and can both be used. My question (which you didn't answer) is which variant should we recommend, and why? I honestly find both `(bytes | str)?` and `bytes? | str?` unpleasant to look at, and the fact that it's not clear which is better makes it even worse. We could even recommend `bytes | str?` but that's even weirder. In contrast, if we don't introduce `?`, then `bytes | str | None` is clear and looks more readable to me; and there's no other variant (you could argue about `None | bytes | str` but that's of the same order as whether to write `bytes | str` or `str | bytes`). All of which IMO is a ding against adding `?`. -- --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...>

Thanks for the feedback. One additional question here: Would anyone like to sponsor this PEP? Thanks, Maggie ________________________________ From: Guido van Rossum <guido@python.org> Sent: Thursday, September 3, 2020 3:18 PM To: Maggie Moss <maggiemoss@fb.com> Cc: typing-sig@python.org <typing-sig@python.org> Subject: Re: [Typing-sig] Update: Work on Optional Syntax PEP Wow, you've been busy! (I know I still owe you a review on the PEP 604 implementation. It's on my TODO list. :-) My main observation at this point is that introducing a new token means that there is no way to use this in code that has to be backwards compatible with Python 3.9 and before (assuming you could get it into 3.10). This is different for PEP 604's `|` operator, which can be used in Python 3.7+ as long as the `from __future__ import annotations` magic import is used to avoid runtime errors on things like `int | str`. The `|` operator could also be used in typeshed, since it is valid Python 3.7 syntax. (While I don't know of any type checkers that currently support it yet, supporting it would not require changes to the Python *parser* -- at least typed_ast can handle it without changes.) However, this shouldn't be a big strike against the proposal. In a few short years Python 3.10 will be the oldest version supported and all will be well. Another concern I have is that we already have two ways to spell "optional": `Optional[T]` and `T | None`. Finally, IMO the argument against `Optional[T]` is stronger than the argument against `T | None`. (But your point that 7% of annotations use Optional is well taken.) --Guido On Thu, Sep 3, 2020 at 12:04 PM None via Typing-sig <typing-sig@python.org<mailto:typing-sig@python.org>> wrote: Hi there, Recently I have been working on an implementation for PEP 604 (https://www.python.org/dev/peps/pep-0604/<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.python.org_dev_peps_pep-2D0604_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=J96mesCJIlD6NfDAAsXL0dFJXR920_vBYasEq8Zgn6A&e=>). While working on this, I started reviewing and exploring what new Optional syntax would look like in the Python language. I've written a rough draft of a PEP and wanted to present it to this email list before submitting a PR. I know this is a topic that has been discussed in many settings (Github issues, in person typing meetups, etc. )previously, and wanted to solicit feedback here first. Let me know if submitting a PR would be a better way to gauge sentiment and feedback on this proposal. Draft Proposal (branch compare): https://github.com/python/peps/compare/master...MaggieMoss:optional-syntax-p... Gist: https://gist.github.com/MaggieMoss/c848cb3a581979f445d075c15629c950 Thanks again, Maggie _______________________________________________ Typing-sig mailing list -- typing-sig@python.org<mailto:typing-sig@python.org> To unsubscribe send an email to typing-sig-leave@python.org<mailto:typing-sig-leave@python.org> https://mail.python.org/mailman3/lists/typing-sig.python.org/<https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.python.org_mailman3_lists_typing-2Dsig.python.org_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=ZeTEN7ql-2_nV4tE3l7PRyEUj6YjwgYR2QlFR3F9QRs&e=> Member address: guido@python.org<mailto:guido@python.org> -- --Guido van Rossum (python.org/~guido<https://urldefense.proofpoint.com/v2/url?u=http-3A__python.org_-7Eguido&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=WzHjojUuk8ytY-7ARrq2LELrpwxQNeOsZCaQ867H_Sk&e=>) Pronouns: he/him (why is my pronoun here?)<https://urldefense.proofpoint.com/v2/url?u=http-3A__feministing.com_2015_02_03_how-2Dusing-2Dthey-2Das-2Da-2Dsingular-2Dpronoun-2Dcan-2Dchange-2Dthe-2Dworld_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=1RqmKCAxL8BNbxJclFdhkTeLb0_yNHHeJBmQLFM3-oQ&e=>

The requirement of having a PEP sponsor is to make sure that poorly thought-out proposals are stopped with minimal waste of resources. Your proposal, even though I am not particularly in favor of it, deserves to be a discussion to have. (For example, it seems that TypeScript is surviving even though it also has this problem of how best to write `Optional[Union[...]]`.) So if you can't find someone else to sponsor it, I will, even though when it comes down to accepting it I would probably recommend that the SC reject it. Even that would be useful, since then we can point to the rejected PEP when the idea is brought up again. :-) Finally -- wouldn't we need to have a new dunder method/protocol so the operator can be overloaded for other functionality? On Wed, Sep 9, 2020 at 3:12 PM Maggie Moss <maggiemoss@fb.com> wrote:
-- --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...>

Yes, I agree that all `|` variants with `?` do not look too pleasant. And that multiple possibilities to write the same things make it even worse. Here I want to show some examples from other languages that already have this feature. TypeScript. It has both `null` and `undefined`. So, there are two syntax constructs to represent it: `| null` and `?` respectively. There's a setting to change this a bit, but let's omit it for now. We are going to use the `--strict` version. function worksWithOptional(param?: number) {} worksWithOptional(1) worksWithOptional(undefined) function worksWithNullable(param: number | null) {} worksWithNullable(1) worksWithNullable(null) function worksWithUnion(param: number | string) {} function worksWithOptionalUnion(param?: number | string) {} function worksWithNullableUnion(param: number | string | null) {} It is clear why TypeScript has both `?` and `| null`, because in JS there are two "empty" states. But, it is also important to highlight that TypeScript does not have this `str? | bytes` vs `(str | bytes)?` problem. It either has a single `?` near the argument / property definition, or union with explicit `null` Flow is a bit different. It allows both `null` and `undefined` to be under `?` when placed in type definition. And also has `?` near arguments / props to mark them to work with `undefined`, but not `null`. See https://stackoverflow.com/questions/50112490/what-is-the-difference-between-... /* @flow */ function foo(x: ?number | string) {} foo(undefined) foo(null) foo(1) function bar(x: ?(number | string)) {} bar(undefined) bar(null) bar(1) function baz(x: number | ?string) {} baz(undefined) baz(null) baz(1) function withOptional(x?: number) {} withOptional(1) withOptional(undefined) It looks way less readable compared to TS. Scala (which is mentioned in the original PEP) (dotty) has only a single way of doing it: `Int|String|Null` https://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html Currently it is in development and things may change. It has no special syntax for `Null`. Scala usually uses the `Maybe` monad to handle empty states, so there's no need for a special syntax. Other languages either don't have `?` syntax (like Scala and Julia), or have different `Null` concepts (like Rust and Haskell), or have different Union concepts (like Swift, Kotlin and Rust), or go really wild in terms of syntax like `T.nilable(T.any(Number | String))` in Ruby or `float() | none()` in Elixir. So, there is nowhere to copy any alternative solutions from. At least in the mainstream languages. My personal opinion: 1. This looks great, way better than now with `Optional`: `def some(arg: str? = None): ...` compare it with ``` from typing import Optional def some(arg: Optional[str] = None): ... ``` 2. This looks a bit less great: `def other(arg: str | None = None): ...` But still pretty pleasant 3. The union solution (2) does scale. It can easily become `str | bytes | None` 4. The `?` (1) solution does not scale well, as I have shown above, `str?` has trouble becoming `str? | bytes` or `(str | bytes)?` (I even don't mention other possible types operators like `&` for intersections that can be added later) чт, 10 сент. 2020 г. в 03:08, Guido van Rossum <guido@python.org>:

Note that in Typescript, the `?` suffix is only accepted in specific constructs and has different semantics than just building an optional type. This can be used to denote optional fields in an interface (somewhat akin to TypedDict) see https://www.typescriptlang.org/docs/handbook/interfaces.html#optional-proper... and denote an optional parameter https://www.typescriptlang.org/docs/handbook/functions.html#optional-and-def..., i.e., the parameter does not need to be explicitly passed to the function. For example, in an interface bar?: number; is not the same as bar: number | undefined; (see playground <https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgPIAczAPYjgGwDFg...> ): interface OptionalFields { foo: number; bar?: number; } const test1: OptionalFields = { foo: 1 } interface RequiredButPossibleUndefinedFields { foo: number; bar: number | undefined; } // This is invalid. Compare it to test1 const test4: RequiredButPossibleUndefinedFields = { foo: 1 } In other type declarations, like generics, one needs to use the full spelling, for example Promise<number | undefined> On Thu, Sep 10, 2020 at 5:31 AM Никита Соболев <n.a.sobolev@gmail.com> wrote:
-- Sebastian Kreft

Thanks so much for the responses to the initial PEP draft. - Shorthand Union + Optional Convention I wanted to address this question:
My question [...] is which variant should we recommend, and why?
Reading through the examples provided, Flow provides syntax most similar to the optional syntax proposed in the PEP. ``` // Flow examples. function foo(x: ?number | string) {} function bar(x: ?(number | string)) {} function baz(x: number | ?string) {} ```
It looks way less readable compared to TS.
In my opinion, this looks less readable because of the placement of the ? operator. For the Python syntax, I would suggest that the convention be to always add the ? at the end of the annotation. ``` # examples def foo(x: int | str?): ... def bar(x: list[int | str?]): ... ``` Of the available options, I find this to be the easiest to digest at a glance, and the most concise. - Dunder Method
Finally -- wouldn't we need to have a new dunder method/protocol so the operator can be overloaded for other functionality?
Yes, thanks so much for this, we would need a new dunder method. I will update the PEP draft and the linked reference implementation. - Sponsorship
So if you can't find someone else to sponsor it, I will, even though when it comes down to accepting it I would probably recommend that the SC reject it. Even that would be useful, since then we can point to the rejected PEP when the idea is brought up again. :-)
I appreciate the honesty. Thanks for offering! :) As next steps, I'll update the PEP draft with these suggestions. Thanks again, Maggie

Wow, you've been busy! (I know I still owe you a review on the PEP 604 implementation. It's on my TODO list. :-) My main observation at this point is that introducing a new token means that there is no way to use this in code that has to be backwards compatible with Python 3.9 and before (assuming you could get it into 3.10). This is different for PEP 604's `|` operator, which can be used in Python 3.7+ as long as the `from __future__ import annotations` magic import is used to avoid runtime errors on things like `int | str`. The `|` operator could also be used in typeshed, since it is valid Python 3.7 syntax. (While I don't know of any type checkers that currently support it yet, supporting it would not require changes to the Python *parser* -- at least typed_ast can handle it without changes.) However, this shouldn't be a big strike against the proposal. In a few short years Python 3.10 will be the oldest version supported and all will be well. Another concern I have is that we already have two ways to spell "optional": `Optional[T]` and `T | None`. Finally, IMO the argument against `Optional[T]` is stronger than the argument against `T | None`. (But your point that 7% of annotations use Optional is well taken.) --Guido On Thu, Sep 3, 2020 at 12:04 PM None via Typing-sig <typing-sig@python.org> wrote:
-- --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...>

Nice. This ? makes sense to me, especially given the similar use in many other languages. Though I wonder how to represent `Union[bytes, str]?` using the | syntax. `(bytes | str)?` or `bytes? | str?`. That should be covered. I believe Thomas Wouters (cc'd) has been mulling over ? as a token for a non conflicting non-typing purpose. Maybe this is the decade of the ?. I'm not worried about being unable to use a new feature on older versions of the language. That is normal, there is always a long time frame before a syntax feature can see wide adoption. (ex: yield, with, set literals, 1_000, async, ...) -gps On Thu, Sep 3, 2020, 3:19 PM Guido van Rossum <guido@python.org> wrote:

Though I wonder how to represent `Union[bytes, str]?` using the | syntax. `(bytes | str)?` or `bytes? | str?`
Good question! From the theoretical point of view, all your examples should be equal. Since Union always maintains its structure. Currently, it works correctly: ``` from typing import Optional, Union x: Optional[Union[int, str]] y: Union[Optional[int], Optional[str]] reveal_type(x) # Union[builtins.int, builtins.str, None] reveal_type(y) # Union[builtins.int, None, builtins.str, None] ``` However, mypy can possibly flatten repeating `None` values, but that's another topic. пт, 4 сент. 2020 г. в 01:48, Gregory P. Smith <greg@krypto.org>:

On Fri, Sep 4, 2020 at 12:14 AM Никита Соболев <n.a.sobolev@gmail.com> wrote:
I know they are equivalent and can both be used. My question (which you didn't answer) is which variant should we recommend, and why? I honestly find both `(bytes | str)?` and `bytes? | str?` unpleasant to look at, and the fact that it's not clear which is better makes it even worse. We could even recommend `bytes | str?` but that's even weirder. In contrast, if we don't introduce `?`, then `bytes | str | None` is clear and looks more readable to me; and there's no other variant (you could argue about `None | bytes | str` but that's of the same order as whether to write `bytes | str` or `str | bytes`). All of which IMO is a ding against adding `?`. -- --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...>

Thanks for the feedback. One additional question here: Would anyone like to sponsor this PEP? Thanks, Maggie ________________________________ From: Guido van Rossum <guido@python.org> Sent: Thursday, September 3, 2020 3:18 PM To: Maggie Moss <maggiemoss@fb.com> Cc: typing-sig@python.org <typing-sig@python.org> Subject: Re: [Typing-sig] Update: Work on Optional Syntax PEP Wow, you've been busy! (I know I still owe you a review on the PEP 604 implementation. It's on my TODO list. :-) My main observation at this point is that introducing a new token means that there is no way to use this in code that has to be backwards compatible with Python 3.9 and before (assuming you could get it into 3.10). This is different for PEP 604's `|` operator, which can be used in Python 3.7+ as long as the `from __future__ import annotations` magic import is used to avoid runtime errors on things like `int | str`. The `|` operator could also be used in typeshed, since it is valid Python 3.7 syntax. (While I don't know of any type checkers that currently support it yet, supporting it would not require changes to the Python *parser* -- at least typed_ast can handle it without changes.) However, this shouldn't be a big strike against the proposal. In a few short years Python 3.10 will be the oldest version supported and all will be well. Another concern I have is that we already have two ways to spell "optional": `Optional[T]` and `T | None`. Finally, IMO the argument against `Optional[T]` is stronger than the argument against `T | None`. (But your point that 7% of annotations use Optional is well taken.) --Guido On Thu, Sep 3, 2020 at 12:04 PM None via Typing-sig <typing-sig@python.org<mailto:typing-sig@python.org>> wrote: Hi there, Recently I have been working on an implementation for PEP 604 (https://www.python.org/dev/peps/pep-0604/<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.python.org_dev_peps_pep-2D0604_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=J96mesCJIlD6NfDAAsXL0dFJXR920_vBYasEq8Zgn6A&e=>). While working on this, I started reviewing and exploring what new Optional syntax would look like in the Python language. I've written a rough draft of a PEP and wanted to present it to this email list before submitting a PR. I know this is a topic that has been discussed in many settings (Github issues, in person typing meetups, etc. )previously, and wanted to solicit feedback here first. Let me know if submitting a PR would be a better way to gauge sentiment and feedback on this proposal. Draft Proposal (branch compare): https://github.com/python/peps/compare/master...MaggieMoss:optional-syntax-p... Gist: https://gist.github.com/MaggieMoss/c848cb3a581979f445d075c15629c950 Thanks again, Maggie _______________________________________________ Typing-sig mailing list -- typing-sig@python.org<mailto:typing-sig@python.org> To unsubscribe send an email to typing-sig-leave@python.org<mailto:typing-sig-leave@python.org> https://mail.python.org/mailman3/lists/typing-sig.python.org/<https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.python.org_mailman3_lists_typing-2Dsig.python.org_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=ZeTEN7ql-2_nV4tE3l7PRyEUj6YjwgYR2QlFR3F9QRs&e=> Member address: guido@python.org<mailto:guido@python.org> -- --Guido van Rossum (python.org/~guido<https://urldefense.proofpoint.com/v2/url?u=http-3A__python.org_-7Eguido&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=WzHjojUuk8ytY-7ARrq2LELrpwxQNeOsZCaQ867H_Sk&e=>) Pronouns: he/him (why is my pronoun here?)<https://urldefense.proofpoint.com/v2/url?u=http-3A__feministing.com_2015_02_03_how-2Dusing-2Dthey-2Das-2Da-2Dsingular-2Dpronoun-2Dcan-2Dchange-2Dthe-2Dworld_&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=f28uZNOWonDFk7FJQDoV1HxAt9325GELs0nSw_fZ-QQ&m=0jLG3fTmrb4AQ6ZhABOSg26ax9ZdSRYxgUFXFZj2kyg&s=1RqmKCAxL8BNbxJclFdhkTeLb0_yNHHeJBmQLFM3-oQ&e=>

The requirement of having a PEP sponsor is to make sure that poorly thought-out proposals are stopped with minimal waste of resources. Your proposal, even though I am not particularly in favor of it, deserves to be a discussion to have. (For example, it seems that TypeScript is surviving even though it also has this problem of how best to write `Optional[Union[...]]`.) So if you can't find someone else to sponsor it, I will, even though when it comes down to accepting it I would probably recommend that the SC reject it. Even that would be useful, since then we can point to the rejected PEP when the idea is brought up again. :-) Finally -- wouldn't we need to have a new dunder method/protocol so the operator can be overloaded for other functionality? On Wed, Sep 9, 2020 at 3:12 PM Maggie Moss <maggiemoss@fb.com> wrote:
-- --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...>

Yes, I agree that all `|` variants with `?` do not look too pleasant. And that multiple possibilities to write the same things make it even worse. Here I want to show some examples from other languages that already have this feature. TypeScript. It has both `null` and `undefined`. So, there are two syntax constructs to represent it: `| null` and `?` respectively. There's a setting to change this a bit, but let's omit it for now. We are going to use the `--strict` version. function worksWithOptional(param?: number) {} worksWithOptional(1) worksWithOptional(undefined) function worksWithNullable(param: number | null) {} worksWithNullable(1) worksWithNullable(null) function worksWithUnion(param: number | string) {} function worksWithOptionalUnion(param?: number | string) {} function worksWithNullableUnion(param: number | string | null) {} It is clear why TypeScript has both `?` and `| null`, because in JS there are two "empty" states. But, it is also important to highlight that TypeScript does not have this `str? | bytes` vs `(str | bytes)?` problem. It either has a single `?` near the argument / property definition, or union with explicit `null` Flow is a bit different. It allows both `null` and `undefined` to be under `?` when placed in type definition. And also has `?` near arguments / props to mark them to work with `undefined`, but not `null`. See https://stackoverflow.com/questions/50112490/what-is-the-difference-between-... /* @flow */ function foo(x: ?number | string) {} foo(undefined) foo(null) foo(1) function bar(x: ?(number | string)) {} bar(undefined) bar(null) bar(1) function baz(x: number | ?string) {} baz(undefined) baz(null) baz(1) function withOptional(x?: number) {} withOptional(1) withOptional(undefined) It looks way less readable compared to TS. Scala (which is mentioned in the original PEP) (dotty) has only a single way of doing it: `Int|String|Null` https://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html Currently it is in development and things may change. It has no special syntax for `Null`. Scala usually uses the `Maybe` monad to handle empty states, so there's no need for a special syntax. Other languages either don't have `?` syntax (like Scala and Julia), or have different `Null` concepts (like Rust and Haskell), or have different Union concepts (like Swift, Kotlin and Rust), or go really wild in terms of syntax like `T.nilable(T.any(Number | String))` in Ruby or `float() | none()` in Elixir. So, there is nowhere to copy any alternative solutions from. At least in the mainstream languages. My personal opinion: 1. This looks great, way better than now with `Optional`: `def some(arg: str? = None): ...` compare it with ``` from typing import Optional def some(arg: Optional[str] = None): ... ``` 2. This looks a bit less great: `def other(arg: str | None = None): ...` But still pretty pleasant 3. The union solution (2) does scale. It can easily become `str | bytes | None` 4. The `?` (1) solution does not scale well, as I have shown above, `str?` has trouble becoming `str? | bytes` or `(str | bytes)?` (I even don't mention other possible types operators like `&` for intersections that can be added later) чт, 10 сент. 2020 г. в 03:08, Guido van Rossum <guido@python.org>:

Note that in Typescript, the `?` suffix is only accepted in specific constructs and has different semantics than just building an optional type. This can be used to denote optional fields in an interface (somewhat akin to TypedDict) see https://www.typescriptlang.org/docs/handbook/interfaces.html#optional-proper... and denote an optional parameter https://www.typescriptlang.org/docs/handbook/functions.html#optional-and-def..., i.e., the parameter does not need to be explicitly passed to the function. For example, in an interface bar?: number; is not the same as bar: number | undefined; (see playground <https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgPIAczAPYjgGwDFg...> ): interface OptionalFields { foo: number; bar?: number; } const test1: OptionalFields = { foo: 1 } interface RequiredButPossibleUndefinedFields { foo: number; bar: number | undefined; } // This is invalid. Compare it to test1 const test4: RequiredButPossibleUndefinedFields = { foo: 1 } In other type declarations, like generics, one needs to use the full spelling, for example Promise<number | undefined> On Thu, Sep 10, 2020 at 5:31 AM Никита Соболев <n.a.sobolev@gmail.com> wrote:
-- Sebastian Kreft

Thanks so much for the responses to the initial PEP draft. - Shorthand Union + Optional Convention I wanted to address this question:
My question [...] is which variant should we recommend, and why?
Reading through the examples provided, Flow provides syntax most similar to the optional syntax proposed in the PEP. ``` // Flow examples. function foo(x: ?number | string) {} function bar(x: ?(number | string)) {} function baz(x: number | ?string) {} ```
It looks way less readable compared to TS.
In my opinion, this looks less readable because of the placement of the ? operator. For the Python syntax, I would suggest that the convention be to always add the ? at the end of the annotation. ``` # examples def foo(x: int | str?): ... def bar(x: list[int | str?]): ... ``` Of the available options, I find this to be the easiest to digest at a glance, and the most concise. - Dunder Method
Finally -- wouldn't we need to have a new dunder method/protocol so the operator can be overloaded for other functionality?
Yes, thanks so much for this, we would need a new dunder method. I will update the PEP draft and the linked reference implementation. - Sponsorship
So if you can't find someone else to sponsor it, I will, even though when it comes down to accepting it I would probably recommend that the SC reject it. Even that would be useful, since then we can point to the rejected PEP when the idea is brought up again. :-)
I appreciate the honesty. Thanks for offering! :) As next steps, I'll update the PEP draft with these suggestions. Thanks again, Maggie
participants (6)
-
Gregory P. Smith
-
Guido van Rossum
-
Maggie Moss
-
maggiemoss@fb.com
-
Sebastian Kreft
-
Никита Соболев