[Python-Dev] Please reject or postpone PEP 526 (original) (raw)
Nick Coghlan ncoghlan at gmail.com
Sun Sep 4 13:59:34 EDT 2016
- Previous message (by thread): [Python-Dev] Please reject or postpone PEP 526
- Next message (by thread): [Python-Dev] Please reject or postpone PEP 526
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 5 September 2016 at 03:23, Ivan Levkivskyi <levkivskyi at gmail.com> wrote:
On 4 September 2016 at 18:43, Nick Coghlan <ncoghlan at gmail.com> wrote:
On 4 September 2016 at 21:32, Ivan Levkivskyi <levkivskyi at gmail.com> wrote: > The first form still could be interpreted by type checkers > as annotation for value (a cast to more precise type): > > variable = cast(annotation, value) # visually also looks similar I think a function based spelling needs to be discussed further, as it seems to me that at least some of the goals of the PEP could be met with a suitable definition of "cast" and "declare", with no syntactic changes to Python. Specifically, consider: def cast(value, annotation): return value def declare(annotation): return object() Nick, If I understand you correctly, this idea is very similar to Undefined. It was proposed a year and half ago, when PEP 484 was discussed.
Not quite, as it deliberately doesn't create a singleton, precisely to avoid the problems a new singleton creates - if you use declare() as written, there's no way to a priori check for it at runtime (since each call produces a new object), so you have to either get the TypeError when you try to use it as whatever type it's supposed to be, or else use a static checker to find cases where you try to use it without initialising it properly first.
Folks can also put it behind an "if 0:" or "if typing.TYPE_CHECKING" guard so it doesn't actually execute at runtime, and is only visible to static analysis.
At that time it was abandoned, it reappeared during the discussion of this PEP, but many people (including me) didn't like this, so that we decided to put it in the list of rejected ideas to this PEP.
Some downsides of this approach: * People will start to expect Undefined (or whatever is returned by declare()) everywhere (as in Javascript) even if we prohibit this.
Hence why I didn't use a singleton.
* Some runtime overhead is still present: annotation gets evaluated at every call to cast, and many annotations involve creation of class objects (especially generics) that are very costly.
Hence the commentary about using an explicit guard to prevent execution ("if 0:" in my post for the dead code elimination, although "if typing.TYPE_CHECKING:" would be more self-explanatory).
* Readability will be probably even worse than with comments: many types already have brackets and parens, so that two more form cast() is not good. Plus some noise of the if 0: that you mentioned, plus "cast" everywhere.
I mostly agree, but the PEP still needs to address the fact that it's only a subset of the benefits that actually require new syntax, since it's that subset which provides the rationale for rejecting the use of a function based approach, while the rest provided the incentive to start looking for a way to replace the type comments.
However, exploring this possibility still seems like a good idea to me, as it should allow many of the currently thorny semantic questions to be resolved, and a future syntax-only PEP for 3.7+ can just be about defining syntactic sugar for semantics that can (by then) already be expressed via appropriate initialisers. I think that motivation of the PEP is exactly opposite, this is why it has "Syntax" not "Semantics" in title. Also quoting Guido:
But I'm not in a hurry for that -- I'm only hoping to get the basic syntax accepted by Python 3.6 beta 1 so that we can start using this in 5 years from now rather than 7 years from now. I also think that semantics should be up to the type checkers. Maybe it is not a perfect comparison, but prohibiting all type semantics except one is like prohibiting all Python web frameworks except one.
It's the semantics that worry people though, and it's easy for folks actively working on typecheckers to think it's just as easy for the rest of us to make plausible assumptions about the kind of code that well-behaved typecheckers are going to allow as it is for you. That's not the case, which means folks get concerned, especially those accustomed to instititutional environments where decisions about tool use are still made by folks a long way removed from the day to day experience of software development, rather than being delegated to the engineering teams themselves.
I suspect you'll have an easier time of it on that front if you include some examples of dynamically typed code that a well-behaved type-checker must report as correct Python code, such as:
x: Optional[List[Any]]
# This is the type of "x" *after* the if statement, not *during* it
if arg is not None:
x = list(arg)
if other_arg is not None:
# A well-behaved typechecker should allow this due to
# the more specific initialisation in this particular branch
x.extend(other_arg)
else:
x = None
A typechecker could abide by that restriction by ignoring variable declarations entirely and operating solely on its own type inference from expressions, so any existing PEP 484 typechecker is likely to be well-behaved in that regard.
Similarly, it would be reasonable to say that these three snippets should all be equivalent from a typechecking perspective:
x = None # type: Optional[T]
x: Optional[T] = None
x: Optional[T]
x = None
This more explcitly spells out what it means for PEP 526 to say that it's purely about syntax and doesn't define any new semantics beyond those already defined in PEP 484.
Cheers, Nick.
-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
- Previous message (by thread): [Python-Dev] Please reject or postpone PEP 526
- Next message (by thread): [Python-Dev] Please reject or postpone PEP 526
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]