I'm excited about PEP 585 https://www.python.org/dev/peps/pep-0585/
Now you can use list, dict, tuple instead of typing.List, typing.Dict, typing.Tuple.
Why wasn't done in the first place? What was the rationale of using typing.List? Did they want to reserve `dict[x]` for some other semantics?
One reason was so the type system could be backported. You can install the typing module all the way back to Python 2.7, where list[int] will never work but nothing prohibits typing.List[int].
The system has been rolled out slowly in general, without hasty changes to the core language.
There's a similar change coming in 3.10: https://docs.python.org/3.10/whatsnew/3.10.html#pep604-new-t...
Any word on if strong typing enforcement will ever happen? I’m sure it’ll only ever be optional but it’s the single biggest wart in the language imo.
Why? Just use mypy and disable Any types. So, it's not longer optional. Then make it so that if mypy fails, your code doesn't run.
test-all:
mypy main.py
pytest test/main.py
This relies on your third party library type annotations being accurate.
That's true of any type system.
No it isn't. In a static type system, you're not relying on annotations because the types are all known statically. But in a dynamic type system, you can have regions of untyped code where the best your third party static analyzer can do is slap "Any" on them and you watch as the precision of your type checking erodes to nothing.
What is
`public static void main(string args)` but an "annotation"?
You can stick "untyped" code in any language. You just have to annotate things with `Object` and cast them.
An annotation is when you write some information and it doesn't directly impact the evaluation of that which it annotates. It's a "note", essentially. Type annotations in Python do not actually affect any aspect of runtime and are ignored during evaluation. This is why you need a third-party tool to look at them. You can actually stick any arbitrary code you like after that colon — it's all ignored just the same.
What you're referring to are called type ascriptions, and they are often seen in what are sometimes called manifest type systems, where you must explicitly write out your types within a static type system. C and Java are common examples of this. These are not annotations because they have real meaning (either used for declaration or for type conversion).
Additionally, there are plenty of statically typed languages which do not require ascription. These languages feature type inference, which is a process that allows the programmer to leave the deduction of the actual types to the compiler. Haskell, Swift, OCaml, Scala, and I think now C++ to some degree (with `auto`) allow for this (to name but a few).
> Type annotations in Python do not actually affect any aspect of runtime and are ignored during evaluation.
This is equally true in Java. Types are erased at runtime. They don't exist in the bytecode.
Just because the type checking and evaluation are done using one tool, "javac" doesn't really mean anything.
Again, what's the difference between a bash script that runs mypy prior to invoking python and a bash script that compiles and runs a java program, from the perspective of type safety, assuming you know nothing about the two programs?
There is no difference. Neither provides any more guarantees than the other. Put another way, by enforcing use of mypy prior to invocation, you convert the annotation to an ascription.
A deeper analysis would suggest that "ascriptions" are actually the things you use to disambiguate when type inference is not powerful enough (https://docs.scala-lang.org/style/types.html).
Scala, for example, calls its type declarations "annotations", except when they are needed to disambiguate, when they are "ascriptions". So under the scala definition, python's annotations are exactly the same as scalas as long as they are used for type checking, which, if you use mypy, they are.
Alright, we've got two different discussions going on here. I'll address them separately.
---
As far as "annotation" vs "ascription", you've actually just reinforced what I said.
> This is equally true in Java. Types are erased at runtime. They don't exist in the bytecode.
Types are erased at compile time, which means that the type-checking analysis has completed. Many compilers erase types after doing type checking to improve runtime performance. That doesn't mean the types don't do anything. They're used for guiding the type-checking by the compiler.
This is in contrast to Python, which does literally nothing with the stuff you throw in the annotations. MyPy doesn't play a role in this specific aspect of the discussion because we're talking about language implementations, and in Python the type annotations are just artifacts in the code that get ignored during compilation and evaluation.
This is the distinction between ascriptions and annotations, which you actually corroborated here:
> Scala, for example, calls its type declarations "annotations", except when they are needed to disambiguate, when they are "ascriptions".
All of the type stuff in Python is handled via annotations because the language proper does not make use of them whatsoever. They're just decoration, really.
In contrast, Java uses all the types to perform type-checking, making them ascriptions.
In languages with lots of type inference, like Scala, you can supply type information. Sometimes these are ascriptions (which either help the inference algorithm or are used for casting), and sometimes they are just artifacts to help the programmer (in which case they can be regarded as annotations, which I didn't address previously).
But the key component in all of this is that we are only looking at the languages proper, not the suite of third-party tools available to those languages, because this is what dictates the correct terminology. In Python the language, types are just annotations which are completely ignored, and this is not the case in statically typed languages.
---
Which brings us to the second point: your original argument.
This thread started with somebody asking whether static typing will ever be implemented in Python proper, to which somebody said there's no reason for that when we can use MyPy and disable support for `Any` types. The response to this was that it would require all third-party libraries to be fully and correctly annotated, where you came in and claimed "that's true in any type system."
The reason I disagreed with this is because in statically typed languages you're not relying on annotations for anything. Keep in mind that we've established that annotations are specifically artifacts in the code that the language itself doesn't care about, because when the language does care they are called ascriptions. Annotations are supplied by the programmer by desire, not by necessity of the language proper.
You can release a fully-functioning Python library with absolutely zero type annotations, and it will run exactly the same as if you annotated everything. This is because type annotations don't do anything in Python; to gain any use from them requires using third-party tools, like MyPy.
But you cannot release a Java library that doesn't have all its types specified in some manner. Because the Java language requires the types to be present, meaning they aren't annotations like they are in Python.
I guess really what I'm trying to get at is that your response where you said "That's true of any type system" was completely missing the point. The point being made by the person you responded to was about how in a Python ecosystem, simply using MyPy and disabling the `Any` type requires all third-party libraries to be fully and correctly annotated — something which is not usually required in Python, so it's an extra burden on the libraries' developers. This is entirely distinct behavior from any statically typed language because in those languages, you can't just leave out the types and call it a day.
Javac uses them to perform type checking, prior to runtime. Exactly the same way that mypy uses them to perform type checking prior to runtime.
> The reason I disagreed with this is because in statically typed languages you're not relying on annotations for anything. Keep in mind that we've established that annotations are specifically artifacts in the code that the language itself doesn't care about, because when the language does care they are called ascriptions. Annotations are supplied by the programmer by desire, not by necessity of the language proper.
But Scala's annotations are used for type checking. Much as python's are if you enable mypy.
> But you cannot release a Java library that doesn't have all its types specified in some manner. Because the Java language requires the types to be present, meaning they aren't annotations like they are in Python.
Of course you can. You can write a functional java library that specifies that all functions take `Object`. Your argument comes down to that syntactically, java requires you stick something in the place-where-type-declarations-go, while python does not.
This ultimately doesn't have any impact on the strictness of the type checking done, because you can stick useless annotations (Any, Object) in the syntactic spot in either case. The semantics are the same.
Ultimately, your argument comes down to "I trust that more third party libraries will have useful types in Java than in python", but that isn't implicit to the type system, it's because the type ecosystem has been around longer.
Which, like, sure. But to say that python doesn't have static typing is silly. Nearly all the python I write is statically typed.
> In Python the language, types are just annotations which are completely ignored, and this is not the case in statically typed languages.
This is a uselessly semantic argument. Much as if you choose to not typecheck your python, you can choose to write essentially untyped java using Object and casts. Are you really certain that no library you depend on does that, or uses reflection to access dynamic and non-statically-verifiable features?
The safety you get from any static analysis tool, whether a type system or a linter or whatever, relies on your dependencies not trying to subvert the tool (or doing so correctly).
This is essentially the argument about rust's Unsafe. You, or any of your dependencies, is free to subvert the borrow checker and do "unsafe" things.
You either have to trust that they are doing so responsibly, or manually verify the correctness of their unsafe code. Having to opt-in to unsafe access is, indeed, an advantage since it makes static analysis of how much "unsafety" there is easy (much as it's easier to find non-static things in vanilla Java than in python), but you can (and some do!) use static analysis to enforce type annotations in python throughout the entire code base.
> so it's an extra burden on the libraries' developers.
It's exactly the same burden as they would have in Java. So I'm not clear on what the point is. Worth noting though, that mypy supports stub files, so you can annotate a third party api yourself (https://github.com/python/typeshed, https://github.com/google/pytype/tree/master/pytype/pytd/std...), so even this claim is ultimately untrue.