Reserve ':=' for type-inferred variable initialization (was PEP 572)
I would like to urge you to reconsider the use of the token ':=' for assignment expressions. The natural interpretation of 'name := expr' is a PEP 526 type-annotated variable initialization 'name : T = expr' with the type annotation T omitted, the tokens ':' and '=' coalesced, and the implied type T inferred as 'type(expr)'. There is an ongoing tendency to introduce possibilities for static analysis into python, perhaps eventually resulting in a statically typed variant of python were (optional) type annotations are enforced (and used for optimizations), and it would be a pity if this specific piece of obvious syntax had been wasted on a comparatively unimportant feature. The following should probably be discussed in python-ideas and would only be relevant for a more distant future, but while I have your attention, here are a couple of thoughts: Distinguishing in a rather unobtrusive way (no 'var' or 'let') the initialization of a previously unbound variable 'name := expr' and the re-assignment of a previously bound variable 'name = expr' would be beneficial in itself (this has been discussed before but AFAIK not with this syntax). For example, 'global' and 'nonlocal' would be redundant and could be deprecated. The use of variable initializations with explicit type annotations as in PEP 526 would only be required in situations where the declared type is deliberately different from the inferred type, e.g. 'any_var: object = 42; any_var = "foo"; #OK, no TypeError'. In the majority of cases a simple 'name := expr' would be sufficient and type-safe. Destructuring initialization, e.g., 'a,b,c: int = range(3)' or 'a,b,c := range(3)', is possible (the annotated or inferred type refers not to the type of the iterable but to the generated type). If it were forbidden (i.e., only a single name-variable allowed) PEP 572 with ':=' could be simply implemented by parsing 'name := expr' as an expression rather than a statement (assuming it is OK to introduce 'name' into the current scope) but destructuring initialization appears to be the more important feature and would make assignment expressions with ':=' ambiguous. Implementation would be straightforward if 'name := expr' were lowered to 'name: auto = expr' where the newly introduced abstract type 'auto' simply acts as a token informing compile-time and/or run-time what to do. An explicit type annotation with type 'auto' could be allowed and would help to teach the feature.
On Apr 26, 2018, at 11:00 AM, Fatty Morgan
wrote: I would like to urge you to reconsider the use of the token ':=' for assignment expressions.
The natural interpretation of 'name := expr' is a PEP 526 type-annotated variable initialization 'name : T = expr' with the type annotation T omitted, the tokens ':' and '=' coalesced, and the implied type T inferred as 'type(expr)'.
PEP 484 type checkers *always* infer the type of an assignment based on the right-hand side's value. The main reason we require PEP 526 annotations at all is when your initial assignment is not useful for this inference. The two most common examples of this are `None` and empty containers. In those cases the type checker is unable to infer what the *intended* value should be, so it urges the programmer to explicitly state it. In this sense, `a := []` or `a := None` doesn't provide any additional information. And `a = 1` is already enough to determine what the expected type is.
The following should probably be discussed in python-ideas and would only be relevant for a more distant future, but while I have your attention, here are a couple of thoughts:
Discussing this here will add to noise for Chris and the BDFL. Consider re-posting in python-ideas. -- Ł
Hi Fatty, and welcome! On Thu, Apr 26, 2018 at 08:00:55PM +0200, Fatty Morgan wrote:
The natural interpretation of 'name := expr' is a PEP 526 type-annotated variable initialization 'name : T = expr' with the type annotation T omitted, the tokens ':' and '=' coalesced, and the implied type T inferred as 'type(expr)'.
I'm not sure why you say that is the "natural" interpretation, unless you're saying that Guido, Chris, myself and dozens of other people taking part of this conversation are unnatural, since none of us thought of that interpretation *smiles* The := token is the second most common assignment operator in programming languages, behind only = single equals sign. For those of us who were raised on Pascal, it is entirely natural to use = for equality tests and := for assignment, and languages that use == for equality are the ones which are weird. Since type-annotations are still only used by a small proportion of Python code and Python developers, I doubt that they will jump to the interpretation of "explicit type hint with no type given". If the type-checker can infer the type of the expression, there's no need to use the colon at all. name := expression # can infer type here name = expression # why not just infer the type here? So using : Type without the type is entirely unnecessary. The colon is only needed when you have to specify a type manually. Your comments about some entirely hypothetical "Python with enforced static typing" are interesting but so blue-sky that I honestly doubt that there's any point in discussing them now. We're focused on Python 3.8 and 3.9, not Python 5 or Python 6. -- Steve
We're focused on Python 3.8 and 3.9, not Python 5 or Python 6.
Hmmm... When I was hearing the repeated belated saying that Python will
never ever jump
on the statically typed ship on each and every static type annotation
discussion I started to
worry this wasn't indeed the case (why the urge of repeating it so much
otherwise?).
Now we got standard library features requiring type annotation and a little
shift
towards a "not now" position.
I'm just wondering... I'm NOT saying this would be bad (or good).
On Fri, Apr 27, 2018 at 2:36 AM, Steven D'Aprano
Hi Fatty, and welcome!
On Thu, Apr 26, 2018 at 08:00:55PM +0200, Fatty Morgan wrote:
The natural interpretation of 'name := expr' is a PEP 526 type-annotated variable initialization 'name : T = expr' with the type annotation T omitted, the tokens ':' and '=' coalesced, and the implied type T inferred as 'type(expr)'.
I'm not sure why you say that is the "natural" interpretation, unless you're saying that Guido, Chris, myself and dozens of other people taking part of this conversation are unnatural, since none of us thought of that interpretation *smiles*
The := token is the second most common assignment operator in programming languages, behind only = single equals sign. For those of us who were raised on Pascal, it is entirely natural to use = for equality tests and := for assignment, and languages that use == for equality are the ones which are weird.
Since type-annotations are still only used by a small proportion of Python code and Python developers, I doubt that they will jump to the interpretation of "explicit type hint with no type given".
If the type-checker can infer the type of the expression, there's no need to use the colon at all.
name := expression # can infer type here name = expression # why not just infer the type here?
So using : Type without the type is entirely unnecessary. The colon is only needed when you have to specify a type manually.
Your comments about some entirely hypothetical "Python with enforced static typing" are interesting but so blue-sky that I honestly doubt that there's any point in discussing them now. We're focused on Python 3.8 and 3.9, not Python 5 or Python 6.
-- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ agriff%40tin.it
On Fri, Apr 27, 2018 at 08:13:20AM +0200, Andrea Griffini wrote:
We're focused on Python 3.8 and 3.9, not Python 5 or Python 6.
Hmmm... When I was hearing the repeated belated saying that Python will never ever jump on the statically typed ship on each and every static type annotation discussion I started to worry this wasn't indeed the case (why the urge of repeating it so much otherwise?).
Only because people keep worrying about it. If we don't deny it, people will think our failure to deny it means it will happen. If we do deny it, they think that our repeated denials means it will happen. We're damned whatever we do.
Now we got standard library features requiring type annotation
We do? Did I miss them? Which std lib features are you referring to? (That's not a rhetorical question -- maybe I have missed something.)
and a little shift towards a "not now" position.
If you're referring to my comment above about "Python 5 or Python 6", perhaps I should have followed my first instinct and written "Python 5000". You know, the Python we get in the year 5000 :-) Guido has said that Python will never *require* type-annotations and static type-checking, and I see no reason to doubt that. But this doesn't rule out a hypothetical runtime option (hence, *optional*) to enforce static type-safety some time in the future. Personally I doubt this will happen: mypy is a non-trivial project itself, by my estimate about 200 .py files, 77000 lines of text, about 60 kloc, and I don't think Guido wants to build it into the reference Python interpreter. And why bother, when it is so easy to add a single dependency (mypy) and integrate it with your work-flow? My point was that reserving syntax for such a hypothetical future Python is a waste of time. Even if it happens, which it probably won't, it won't happen any time soon. By the time this hypothetical future rolls around, who knows what syntax we'll want? -- Steve
On 27 April 2018 at 22:28, Steven D'Aprano
On Fri, Apr 27, 2018 at 08:13:20AM +0200, Andrea Griffini wrote:
Now we got standard library features requiring type annotation
We do? Did I miss them? Which std lib features are you referring to?
(That's not a rhetorical question -- maybe I have missed something.)
Data classes rely on the presence of annotations to spot field declarations (it mostly doesn't care what those annotations actually say, but it does need them to be present in order to create the list of field names). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Fri, Apr 27, 2018 at 10:56:06PM +1000, Nick Coghlan wrote:
On 27 April 2018 at 22:28, Steven D'Aprano
wrote: On Fri, Apr 27, 2018 at 08:13:20AM +0200, Andrea Griffini wrote:
Now we got standard library features requiring type annotation
We do? Did I miss them? Which std lib features are you referring to?
(That's not a rhetorical question -- maybe I have missed something.)
Data classes rely on the presence of annotations to spot field declarations (it mostly doesn't care what those annotations actually say, but it does need them to be present in order to create the list of field names).
Thanks Nick. But they're not exactly used as *type* annotations. It was inevitable that something in the std lib would eventually make use of annotations, but unless they're used for type-checking, that's hardly eating away at the promise "no mandatory static typing". -- Steve
On 4/27/2018 8:28 AM, Steven D'Aprano wrote:
On Fri, Apr 27, 2018 at 08:13:20AM +0200, Andrea Griffini wrote:
Now we got standard library features requiring type annotation
We do? Did I miss them? Which std lib features are you referring to?
(That's not a rhetorical question -- maybe I have missed something.)
Presumably dataclasses and typing.NamedTuple. Eric
Fatty Morgan wrote:
Distinguishing in a rather unobtrusive way (no 'var' or 'let') the initialization of a previously unbound variable 'name := expr' and the re-assignment of a previously bound variable 'name = expr'
That would be a massively confusing change. It's a fine idea for a new language, but I can't see a smooth way to get there from existing Python. -- Greg
participants (7)
-
Andrea Griffini
-
Eric V. Smith
-
Fatty Morgan
-
Greg Ewing
-
Lukasz Langa
-
Nick Coghlan
-
Steven D'Aprano