
Hi typing-sig, not sure if this is the correct place to post this. If it isn't, I'd be happy to be guided to the correct place. Anyways, here goes: I'm using Literal a lot for constants/magic numbers, both internally and when referring to constants/#defines used in foreign C functions. And I have one major gripe with them: they are unnecessarily verbose because they require writting everything twice. # +++++ CODE BLOCK START +++++ # Example: some constants from winuser.h used in windll.user32.MapVirtualKeyW MAPVK_VK_TO_VSC: Literal[0] = 0 MAPVK_VSC_TO_VK: Literal[1] = 1 MAPVK_VK_TO_CHAR: Literal[2] = 2 MAPVK_VSC_TO_VK_EX: Literal[3] = 3 MAPVK_VK_TO_VSC_EX: Literal[4] = 4 # +++++ CODE BLOCK END +++++ As you can see, every literal needs to be written twice to conform with the type annotation syntax as it currently is. Similar to the type inference for basic Final annotations without [<type>], I'd like to propse allowing the usage of basic Literal annotations without [<value>] if they are annotated and assigned on the same line. So these two lines would both result in MAPVK_VK_TO_VSC having the Literal[0] type hint. # +++++ CODE BLOCK START +++++ MAPVK_VK_TO_VSC: Literal = 0 MAPVK_VK_TO_VSC: Literal[0] = 0 # +++++ CODE BLOCK END +++++ For the implementation detail, I would err on the side of caution and only allow this notation in basic "variable: Literal = value" form. More complex forms like "variable: tuple[Literal, Literal] = [0, 1]" don't strike me as worthwhile enough to consider the additional implementation overhead/complexity. There are already enough things to consider, even with just the basic form. See the following two approaches. Approach A: If a naked Literal annotation is found, type checkers should ideally use the right hand side of the expression and treat it as if it was copied into the Literal[ ] annotation by the user. # +++++ CODE BLOCK START +++++ def get_value() -> Literal[0]: ... var different_literal: Literal[Color.RED] = Color.RED var non_literal: Final[bytes] = b'data' var: Literal = "value" # legal var: Literal["value"] = "value" # equivalent expression var: Literal = get_value() # should be treated as error and flagged by type checkers, even if get_value() returns Literal types. var: Literal[get_value()] = get_value() # equivalent expression, showing why it's an error var: Literal = different_literal # should be treated as error and flagged by type checkers, var: Literal[different_literal] = different_literal # equivalent expression var: Literal = non_literal # should be treated as error and flagged by type checkers, var: Literal[non_literal] = non_literal # equivalent expression # +++++ CODE BLOCK END +++++ This is probably the simpliest to implement, since it requires no inference of the right hand side. A non-literal, even another variable with Literal annotation would simply be treated as illegal. Approach B: Infer the value of the Literal to insert based on the right hand side's annotation. # +++++ CODE BLOCK START +++++ var: Literal = "value" # legal var: Literal["value"] = "value" # equivalent expression var: Literal = get_value() # legal, since the naked Literal would look for the annotation of get_value() and get Literal[0] var: Literal[get_value()] = get_value() # equivalent expression, showing why it's an error var: Literal = different_literal # legal, since the naked Literal will look up different_literal's annotation and get Literal[Color.RED] var: Literal[different_literal] = different_literal # equivalent expression var: Literal = non_literal # not sure about this one, looking at current behavior when assigning a Final to a Literal, mypy would flag it, pyright would treat non_literal as a literal when possible. var: Literal[non_literal] = non_literal # equivalent expression # +++++ CODE BLOCK END +++++ I'd be fine with any approach, since both solve my basic use case of reducing duplicated code. I've scanned through PEP 586 (Literal Types), and I found no mention on why "naked" Literal should be disallowed, indicating to me that it was simply never considered. (Which is not surprising, since most examples in that PEP are using Literal in function argument or return types, where the simple syntax would not apply) Under the point "Adding more concise syntax", it simply mentions skipping on Literal completely is not an option. This proposal still requires the Literal annotation, it simply extends its usage in a minor way that doesn't break grammar. I'd appreciate any feedback on angles that I might have missed while investigating the feasability of this propsal. Best wishes, Jakob