On Tue, Jun 8, 2021 at 11:19 PM Tal Einat <taleinat@gmail.com> wrote:
On Tue, Jun 8, 2021 at 11:09 PM Guido van Rossum <guido@python.org> wrote:
On Tue, Jun 8, 2021 at 11:40 AM Sebastian Rittau <srittau@rittau.biz> wrote:
Am 08.06.21 um 18:51 schrieb Guido van Rossum:
Why do type checkers have to special-case sentinels? Until this idiom has become popular, using `Literal[SENTINEL]` seems the most logical approach. The only change to type checkers in that case would be to treat `sentinel` as one of the types whose values can be used in `Literal[]`.

Unless I misunderstand something (quite possible!), the following idiom does not currently work with type checkers and is not supposed to work:

    X = foo()
    def bar(x: Literal[X]) -> None: ...

This means that "X = sentinel()" would need to be special-cased.


Hm, I think you're right. I was thinking of

X = 42

def bar(x: Literal[X]):
    ...

but I don't even know if that works, and even if it did, it wouldn't work if you replaced 42 with a call to int(...).

The precedent here is Enum values. How does Literal work with Enum values? Could sentinels use the same mechanism?

Enums have a considerable amount of special-casing, both at runtime and in static checkers. Basically, when comparing Color.RED and Color.BLUE, the static checker knows that these are not the same value. (With the exception of aliases, I'm not sure how those work.) But when you compare Color(x) and Color.RED, the checker doesn't have enough information to tell whether they are the same, and will always give you an error. (The same as when you take a value of type int and try to match it against Literal[42].)

Without special-casing the static checker wouldn't know whether X and Y could be the same or not if you write

X = sentinel()
Y = sentinel()

and it also wouldn't know that X cannot be changed to a different value.

Maybe it could be made to work if you write

X: Final = sentinel()

but this would require an extension of the concept of Literal[], which, as currently defined, only supports a few types (IIRC bool, int, str, and enums). I think it doesn't even support aliases, so

X: Final = 42

does not make X compatible with Literal[42] (though I'm not sure of that).

(Can you tell I'm not set up to try anything out? Nor do I feel like re-reading the PEP... :-)

--
--Guido van Rossum (python.org/~guido)