7 ms·
> not-very-educated thoughts on gradual typing This seems like an inaccurate and condescending put-down. What is the definition of "educated" in this context?
by civilized 5y ago
> not-very-educated thoughts on gradual typing
This seems like an inaccurate and condescending put-down. What is the definition of "educated" in this context? Is there a book or generally well-known resource?
The author is clearly thoughtful and curious. Near the top of the post he says "what I’m hoping for is that someone will come along and tell me that I got it all wrong. “When you do it as follows, the system works: $explanation” Because, you know, I’d really like to have static typing in Python."
> 1. If you're using a dynamic language, then _by definition_ the language will not enforce your static hints at runtime. However, good news! Python has always been strongly typed, and _does_ enforce types at runtime!
And yet, the author points out that this is a working program:
foo: int = 'hello'
print(foo)
In what reasonable sense can Python be said to "enforce types at runtime" here?
- ledauphin 5y agoThis 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.
- the_af 5y agoI agree with most of your comment, but I think there's a miscommunication problem here. When Python "enforces types at runtime" this is the actual types, not type hints. Type hints are not a runtime artifact. The "actual type" here is "string", and enforcing it means Python would not allow invalid operations on it without error'ing. A programming language that will let you do basically anything to any value because it doesn't enforce type safety is of course C. Python is safer than C.
- AnimalMuppet 5y agoYes and no. C will let you do things like: *(unsigned long*)0xFFFFFF14 = 0x749235f8; It will not let you do things like: *0xFFFFFF14 = 0x749235f8; or char* s = "abc"; *(unsigned long*)0xFFFFFF14 = s; It also won't let you call thing.method without thing.method definitely existing. Best of all, all of these are enforced at compile time. Now, C absolutely will let you convert an int to a pointer, or a char to an int, or an array to a pointer, or... well, it will let you convert lots of things to lots of things. Some of those things are unsafe unless you are quite sure what you're doing. > A programming language that will let you do basically anything to any value because it doesn't enforce type safety is of course C. False on several grounds. You can't call something that isn't a function. You can't call a function on something that doesn't have it. You can't use an int as a pointer or an array without casting it. You can't use an int as a dict (not that C has any built-in idea of what a dict is...) > Python is safer than C. Depends on what you're doing, and what kinds of errors you are more prone to.
- the_af 5y agoI find this level of nitpicking puzzling. You know what I meant and what error I was clarifying for the comment I was replying to. Yet you went out of your way to point all sorts of irrelevant mistakes in my post, when the gist of it was right. Do you feel it was more important to correct me on these trivial things, or was my reply more or less correct when fixing the conceptual error in this sentence?: > "In what reasonable sense can Python be said to "enforce types at runtime" here?" Here's a nitpick of my own to your post: > "Some of those things are unsafe unless you are quite sure what you're doing." Wrong. Type (un)safety does not depend on you "being quite sure of what you're doing". PS: assume I know C and that I've programmed complex things using it. No need to catch yourself with statements like "not that C has any idea of what a dict is". Assume we are both C programmers. It will make you sound more polite.
- ungawatkt 5y agoFor 1, there's some unfortunate but important semantics. Python does not enforce type _Hints_ at runtime, as Hints are in many ways fancy comments. But as pointed out, python is a strongly typed language (at least on the sliding scale of strong to weak), and types are known at runtime (call `print(type(var))` to see them). And calling `1 + 'a'` will result in a TypeError exception, unlike say JavaScript. I believe this is the relavent passage in the article the GP is referencing, which is incorrect if you take "runtime" to mean something like when the line is executed: "Python is a dynamically typed language. By definition, you don’t know the real types of variables at runtime." It _is_ however correct to say you don't know the real type _before_ runtime, at least python does not.
- ImprobableTruth 5y agoI think the top comment was less polite than it should be, but I would echo that the post seems to have a bit of a weird understanding of gradual typing? The Any type is to allow incremental typing. You start out with dynamic code, and progressively 'typify' it by adding more and more annotations, with Any working as a stopgap where for the moment no valid type exists, until you finally have a fully typed program. Inserting Anys because you're lazy is like casting things to Object in Java because you're lazy, abusing it like that is just incredibly sloppy and bad code. If someone is really struggling with this, simply use a linting rule to ban Any in 'mature' code.
- ZephyrBlu 5y agoLike the author said, the weird thing is that it goes both ways. I'm pretty sure if you try to return `any` from a function with an explicit return type in TypeScript you'll get pinged for it.
- derekbaker783 5y agoNot with any TSC settings I've ever used.
- MBCook 5y agonoImplicitAny is a very common config option that helps catch a ton of bugs. I wouldn’t use TS without it.
- mikewhy 5y agonoImplicitAny is different than what's being discussed (I think). Returning something typed as `any` in a function that has a different return type is totally fine: it's not implicit (you've cast it to any), and it passes (you're saying the type is literally anything after all). There are lint rules to avoid typing as `any`.
- DangitBobby 5y ago
- sevensor 5y agoPython enforces its runtime types at runtime. 'hello' is a perfectly valid argument to print. Python will raise a TypeError if you try to use it to index a list though.
- woodruffw 5y ago> In what reasonable sense can Python be said to "enforce types at runtime" here? Python is both strongly typed and protocol-typed. In the case of `print(...)`, the protocol is that the received parameter responds to `str(...)` (i.e., has `__str__`). (What Python isn't is statically typed. But "strong" and "static" are completely different typing dimensions.)
- reikonomusha 5y agoI think the person you're responding to means to ask > In what reasonable sense can Python be said to "enforce statically declared types at runtime" here? which is certainly an extremely pertinent question for a language that allows declaring supposedly static qualities of a program.
- woodruffw 5y ago> In what reasonable sense can Python be said to "enforce statically declared types at runtime" here? It can't, because Python doesn't have statically declared types. It's a strong, dynamically typed language. Python also doesn't allow you to declare static types. It allows you to declare type hints, which are a sort of adjacent and potentially unrealistic (or just plain incorrect) typechecking proof that doesn't correspond at all to runtime behavior.
- reikonomusha 5y agoIf your statement were absolutely true then a product like mypy would neither exist nor provide value. Python has the capacity to have some form of gradual typing built-in at the language level, but it does not, which has led to the enormous confusion we have before us. The SBCL implementation of Common Lisp is a great example of a strong, dynamically typed language that is able to, when possible, detect errors statically at compile time. That tech is 30 years old now. There is no reason why the Python bytecode compiler could not statically or dynamically detect this programmer error at either compile-time or run-time present in this statement: x: int = "x" Compare to Common Lisp, well known for being dynamically typed (so dynamic that it's possible to change the class of an object at run-time!): (declaim (type integer x)) (defvar x "oops") ; ==> Unhandled SIMPLE-TYPE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {10005D05B3}>: Cannot set SYMBOL-VALUE of X to "oops", not of type INTEGER. quitting compilation unit aborted caught 1 fatal ERROR condition Instead, this job in Python is haphazardly relegated to the program readers and IDE implementers.
- linsomniac 5y agoPython can't be said to enforce types at runtime. AFAIK, it doesn't say that. In fact, the original article starts off with "I'm expecting to be able to run a static analyzer", then it goes on to say "This isn't caught at runtime". Yes, but is it caught at static analyzer run? Yes, I typed it into vi and ran mypy on it and it said "error: Incompatible types in assignment (expression has type "str", variable has type "int")." But I didn't have to run mypy on it, my editor told me: "Expression of type "Literal['hello']" cannot be assigned to declared type "int"". Maybe the word "educated" wasn't the right choice in this case, can you offer a better one? I honestly couldn't make it through the entire article, despite several attempts. It is full of inconsistencies and what seem like wilful misunderstandings to justify the authors conclusion. Particularly as the author starts off saying "run a static analysis tool" as if knowing that's how you go about it, and then saying "it doesn't catch it at runtime".
- fer 5y ago> Python can't be said to enforce types at runtime. It does: in form of TypeError exceptions. It doesn't enforce type hints, sure, but that's why they're called hints and not declarations.
- heavyset_go 5y ago> In what reasonable sense can Python be said to "enforce types at runtime" here? In [1]: foo: int = 'hello' In [2]: foo + 1 TypeError Input In [2], in <cell line: 1>() ----> 1 foo + 1 TypeError: can only concatenate str (not "int") to str
- bscphil 5y agoExactly right, great example. And furthermore: >>> foo: int = 'hello' >>> type(foo) <class 'str'> Python's type annotations are annotations. Types are being enforced at runtime, it's just that some are thinking that annotations have some effect on the interpreter, when they do not.
- reikonomusha 5y agoThis is a demonstration that it has not enforced what many would reasonably believe is a static type declaration. But we have (to quote another commenter) "uneducated" people making a supposedly boneheaded mistake to assume x: T = y is a declaration that x will only contain values of type T, or otherwise something will be detected by cpython as invalid (at either bytecode-compile-time or run-time). Instead, this line is more properly interpreted as "documentation reasonably believed to represent a type saying something about values that x can be assigned at runtime, that's not in a docstring, that some programs may query." I can totally forgive anybody who believes the former over the latter, and expresses their belief in a statement like that which you've quoted.
- woodruffw 5y agoType hints are not static type declarations. Python does not refer to them as such, nor does Mypy or any other typechecker for Python type hints. Absent of active machine checking (e.g., via mypy), type hints should be considered exactly what you said: another form of documentation, one that might just be wrong.
- reikonomusha 5y agoThis is my point precisely: it looks like a static type declaration to anybody who has seen what a static type declaration looks like in any statically or gradually typed program in the last 50 years. But in Python, it's not (and documented in a PEP as not), and it causes massive confusion.
- d0mine 5y agoDon't confuse strong typing and static typing. Python is strongly typed. It respects types at runtime e.g., `"1"+1` causes TypeError. Python is not statically typed. For comparison, C is statically typed but it is weakly typed e.g., printf function has no idea about actual types of its arguments (in particular, errors in the format arg may produce non-sensical results silently).
- bayesian_horse 5y agoThe "print" function will take any Python object and call its "__str__" method. Not sure if it will do it to a string, but the outcome would be the same. As far as I remember, the "__str__" method is present on all objects in some form, so print will happily take any type.
- smohare 5y agoCome on. It’s uneducated because it’s just a naive hot take. The education in this case comes from experience and basic understanding of the underlying issues. The author does not demonstrate possessing either of these attributes.