4 ms·
This one is self-explanatory. Can a string be printed? Yes! Then Python is (correctly) allowing typesafe behavior here. Your (incorrect) annotation does not in
by ledauphin 5y ago
This one is self-explanatory.
Can a string be printed? Yes! Then Python is (correctly) allowing typesafe behavior here. Your (incorrect) annotation does not in any way contradict the typesafe-ness of printing a string (or an int). They're both equally printable.
This is just a very, very bad example, plain and simple. It 'looks' bad to a superficial reading, but in practice it demonstrates only what is already known about static typing in Python - it is enforced (or not) separately from the interpreter.
- the_af 5y agoAgreed. Static typing is usually enforced during the compile stage in other languages. It's specifically meant to catch problems before running the code (hence the "static" in its name). This said, I find the linting/type-hint-checking stage of Python cumbersome and confusing :(
- civilized 5y agoIt seems that your point boils down to "Python enforces types at runtime if you define 'enforce types at runtime' not to include 'enforcing that data you declare to be of a certain type actually is of that type'". Am I the only one baffled by this way of thinking?
- ledauphin 5y agoPython does and always has enforced types at runtime. This is called duck-typing. If you're not familiar with the concept of strong+dynamic, it is easy to see how this could be confusing. This may help. https://stackoverflow.com/questions/2351190/static-dynamic-vs-strong-weak https://stackoverflow.com/questions/2351190/static-dynamic-v... Static type annotations by definition are not enforced at runtime. This has been true of every language that has ever used static typing, including C, C++, Java, Rust, Typescript... you name it, statically typed languages only enforce their static typing at compile/analysis time. Yes, it is possible to annotate types in Python incorrectly. It's possible to do this in all other languages that allow type-unsafe behavior (whether natively or via reflection, etc). This may be less common in some languages than in others, but it is fundamentally possible in the vast majority of languages that perform static typing, because those types are fundamentally enforced at analysis time, not runtime. The author of the article seems to be unfamiliar with these distinctions, and maybe you are too. It's fair to complain that these distinctions are confusing and make things harder for programmers. Nevertheless, very few languages have ever been designed with a type system that acts exactly the same at analysis time and runtime. It's a very difficult problem, partly because these are all abstractions from the perspective of the underlying computer, which only understands boolean logic and integer/floating point math, and has virtually no other notion of types in any formal sense. Type systems are a complex topic, and as someone who has been paying attention to them for a while, it's frustrating to see uninformed discussion of them show up on Hacker News. That said, it's perfectly understandable that people are confused by these distinctions, and rest assured there's a lot of effort going into developing better languages that suffer _less_ from these issues. For the everyday working programmer, however, there are currently lots of tradeoffs to be made, and Python's approach to static+dynamic typing is actually pretty usable, all things considered, which is why the community overall has embraced the new static typing despite its blemishes.
- the_af 5y ago> Yes, it is possible to annotate types in Python incorrectly. It's possible to do this in all other languages that allow type-unsafe behavior (whether natively or via reflection, etc). This may be less common in some languages than in others, but it is fundamentally possible in the vast majority of languages that perform static typing, because those types are fundamentally enforced at analysis time, not runtime. It is pretty damn hard to make this mistake in languages that enforce static typing. I mean, you would have to go out of your way to do so. In Python, however, it is trivial to write the wrong type signature or to modify the body of a function so that it no longer matches the signature. "Fundamentally possible but terribly unlikely, as opposed to the Python way of doing it" would be a more accurate description.
- ledauphin 5y agoI think your (and the article's) argument could be summarized as "static type annotations without automated enforcement by actually running a type checker considered harmful". Since this argument is not meaningfully different from "comments that are lies considered harmful", it seems fair to expect reasonable people to dismiss it as uninteresting.
- the_af 5y ago> it seems fair to expect reasonable people to dismiss it as uninteresting. Do you think that's a fair treatment of someone who disagrees with you but has been respectful of your opinion so far? I realize proglang debates are flamewar territory. But I have been very careful to state I find Python type hints puzzling and less useful than they should be. It is obviously an interesting opinion shared by many others, not just me or the article's author. As a fan of statically typed languages, I do indeed find some Python programmers engage in a form of Stockholm's syndrome. It usually takes the form of the assertion "I never found a bug that was a type error". Have you or anyone you know ever said this? In my mind, the opposite statement of the one you attribute to me would be "wishful thinking and a positive attitude is enough to catch mistakes, it's not necessary to have help from automated tooling". In this day and age, I cannot disagree more.
- reikonomusha 5y agoNo, you're not the only one. All of these gymnastics to justify the behavior of the string-declared-int baffle me. Is it "legally" baffling, i.e., do I understand why this behaves in the way it does purely mechanically, and do I understand the arguments the gymnasts are making? Yes. But from an idiomatic, colloquial, linguistic, syntactic, programming-historical, or programming-cultural standpoint? Baffled. Even calling it gradual typing is baffling. It's just adding metadata-that-doesn't-look-like-metadata that sophisticated programs that aren't part of the Python bytecode compiler can use. The definition I know is the same one from Wikipedia: > Gradual typing is a type system in which some variables and expressions may be given types and the correctness of the typing is checked at compile time [...] This is definitely not what Python is doing.
- throwaway287391 5y ago> This is definitely not what Python is doing. Maybe not by default but there is tooling that makes it work that way — that’s exactly how the python build system works at my company. I don’t know the details but when I “build” python code (creating bytecode pyc files) it produces compiler errors and fails to build if I e.g. try to pass an int to an f(x: str). This has usefully caught bugs before I ran some expensive/time-consuming scripts. I guess you could say this doesn’t count as it’s a separate program doing the type checking but IMO there’s not a clear distinction between that and e.g. having a first type checking pass in the “same” compiler program.
- reikonomusha 5y agoI don't know the latest but PEP 484 writes: > While these [type] annotations are available at runtime through the usual __annotations__ attribute, no type checking happens at runtime. Instead, the proposal assumes the existence of a separate off-line type checker which users can run over their source code voluntarily.
- throwaway287391 5y agoRight, it’s definitely still a voluntary feature. What I meant is if you opt in and make it part of your project’s standard build procedure for python code, you effectively get the behavior and benefits of “compile-time type checking” (to the extent that you actually use type annotations in your code).
- School-Cotton 5y agoThis is how all or most statically-typed languages work, too. The typing is purely a compile-time construct. E.g. this kind of code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn%20make_fake_vec()%20-%3E%20Vec%3Cusize%3E%20%7B%0A%20%20%20%20unsafe%20%7B%0A%20%20%20%20%20%20%20%20std%3A%3Amem%3A%3Atransmute(%22Hello%2C%20World!%22.to_string())%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20string%3A%20String%20%3D%20unsafe%20%7B%0A%20%20%20%20%20%20%20%20std%3A%3Amem%3A%3Atransmute(make_fake_vec())%0A%20%20%20%20%7D%3B%0A%20%20%20%20%0A%20%20%20%20println!(%22%7B%7D%22%2C%20string)%3B%0A%7D https://play.rust-lang.org/?version=stable&mode=debug&editio... typically works fine (or worse, works fine in debug mode and causes unpredictable UB-related bugs in release mode). std::mem::transmute here is a no-op at runtime; all it does is subvert the static type checker. The difference between statically-typed languages and things like Python with type hints is _not_ that the former has any runtime type checking; it’s that subverting the (static!) type system is more difficult and requires more obvious ceremony, and that static type checking is required whereas with Python it’s optional. If you hacked rustc to disable static typechecking you would get a similar experience to Python with type hints but without any mypy-like tools. (Of course, this would be hard to do in practice, because Rust, like most statically-typed languages, uses types not just for typechecking but also for code generation and method dispatch.)