10 ms·
this article is so full of... not-very-educated thoughts on gradual typing in a dynamic language that it's hard to know where to start. A few concrete criticis
by ledauphin 5y ago
this article is so full of... not-very-educated thoughts on gradual typing in a dynamic language that it's hard to know where to start.
A few concrete criticisms:
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!
2. A number of the examples given would be _impossible_ to statically type in most compiled languages (those without dependent types). It's hard to know where to go with a critique saying that you can't fully represent heterogeneous values in a dict, given that you can't do this _at all_ in many statically compiled languages.
It seems to fall back on saying "use of the type system requires too much discipline to be useful". This might be an interesting criticism on its own; however many current users of Python can say, from experience, that the required discipline is not a high enough hurdle that it prevents us from using types consistently and correctly.
There is plenty to critique about Python's static typing, but this article would have been better titled "I'm confused about Python's static type system and want somebody to show me how it's actually used in real-world scenarios".
- moonchild 5y ago> If you're using a dynamic language, then _by definition_ the language will not enforce your static hints at runtime What definition is that? Raku is a dynamically language with gradual typing which will enforce those types at runtime (if it cannot do so at compile time).
- Matheus28 5y ago> you can't do this _at all_ in many statically compiled languages What statically compiled language doesn't provide a way (sometimes clunky) to have heterogeneous values in a dict? You can do that with void* in C, even
- dtech 5y agoIt seems to me like Python needs to get Typescript's capabilities (if Python wants to go further this way of course). It solves all these problems very well, and has no problem with 2 and most of the author's objections.
- ledauphin 5y agoTypescript does absolutely fantastic type inference, which mypy definitely does not. I think that's a huge advantage for Typescript over mypy, and it's really foundational to the value it provides. However, even in Typescript it is nontrivial to _annotate_ these complex types, and in most cases it's still possible to do in Python - you just need to commit to using something like dataclasses rather than pretending that what you have is a `dict`. Basically, to get the most out of static typing in the world of Python, you do have to write more boilerplate than you would in Typescript, and in particular you need to avoid dicts and prefer various sorts of class-based data containers (again, dataclasses, attrs, namedtuples, etc).
- eyelidlessness 5y ago> However, even in Typescript it is nontrivial to _annotate_ these complex types The only one which stands out to me as non-trivial in TypeScript is thrown exceptions… and even then only because you can only type them in a catch clause, and only with unknown, and they’re invisible to callers. But then this is why people who would care for checked exceptions quite reasonably just use something like a Result type. But I agree with your conclusion completely, and it’s basically the same one I came to reading the post. I was curious about how the current state of things compares to TS, as I may soon have a foray back into Python soon, and would be delighted to bring some static types into the mix. Pretty much as I expected, it’ll probably be more effort/less valuable than TS, but more valuable to me than to the author.
- strogonoff 5y agoI had to come back to Python after working with TypeScript for a while. After going from Python 2.x to TypeScript and being very impressed with static typing, I didn’t want to go back to untyped so I had to get up to speed with the ecosystem. My findings: — Consider using Pydantic (either its drop-in dataclasses replacement, or its models). It has issues and documentation is lacking in places, but in many use cases it’s a boon when it comes to being confident about data you read and/or pass around. — Don’t use TypedDict if you foresee needing anything like optional keys, especially with defaults. I went with TypedDict and it came back to bite me later (though was relatively easy to refactor). — Keep an eye on https://pypi.org/project/typing-extensions/ https://pypi.org/project/typing-extensions/, it has some useful utility types. I wish I knew about this package a couple of months back. — If you use VS Code (which I started after switching to TS), there’re some shenanigans to be aware of. Unlike TypeScript’s elegant approach where you’re in control of installing typing versions, VS Code’s official Python extension will force-install unvetted third-party typings, not caring if they don’t match library versions in your use and not allowing to opt out. In later versions you can unset mypy in Python extension settings, and use a separate Mypy extension that doesn’t do this behind your back and doesn’t send you deep into some rando’s typings when you hit F12 to jump to definition. — That aside, VS Code can provide development experience is not that far from TypeScript. You can keep a virtualenv nearby and select its Python bin as interpreter in your workspace, giving Mypy access to dependencies (and if VS Code’s interpreter selection GUI resolves symlinks, you can enter interpreter path by hand so that it doesn‘t). — Sphinx documentation is good at picking up typing hints and works reasonably well with Pydantic’s models, too.
- zmgsabst 5y agoThat’s the point though: Duck typing and heterogeneous dictionaries are (and have been) standard Python. Adding a type system which doesn’t respect duck typing by trying to access the member even when the types don’t match or which can’t express standard idioms used in Python seems a poor architectural choice. It’s not saying that Python’s type system is “too much discipline”, but rather that the type system doesn’t encode typical Pythonisms.
- Znafon 5y agoPython typing supports duck typing: https://peps.python.org/pep-0544/ https://peps.python.org/pep-0544/ and heterogeneously typed ducts: https://peps.python.org/pep-0589/ https://peps.python.org/pep-0589/
- Spivak 5y agoAnd you can make it work at runtime too! So as long as you have the right methods and attrs isinstance on your duck-typed object will return true!
- zmgsabst 5y agoI read 0544 and the proposal for protocols fails to support the main benefit of duck typing, as it requires the substituted-for class to be defined as a protocol. Traditionally, duck typing is used to inject types into a library that isn’t expecting extension at that particular point — eg, substituting a test class for a real class in a data object that normally wouldn’t be a protocol. I’m not seeing how that PEP addresses that use case. - - - - Similarly, the heading on the dictionary says “for a fixed set of keys” — but what if I want a dynamic heterodox dict? Eg, unpacking JSON. You just end up shoving “any” all over the place. At which point, are the types helping? Though, protocols do help the dict case for typing: dict : Hashable -> Any
- ljojiasdf 5y agoCan you re-read please? https://peps.python.org/pep-0544/#:~:text=Structural%20subtyping%20is%20natural%20for,have%20their%20strengths%20and%20weaknesses https://peps.python.org/pep-0544/#:~:text=Structural%20subty.... > substituted-for class to be defined as a protocol. ... which is false > Similarly, the heading on the dictionary says “for a fixed set of keys” — but what if I want a dynamic heterodox dict? Eg, unpacking JSON. You can quite obviously decode to recursive types (e.g. using pydantic), not sure what the problem is.
- 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?
- the_af 5y agoI can only speak about my own experience: Most people I know writing Python don't use type hints because they are too much of a hurdle for very little payoff. The tooling that pays attention to type hints is slow as molasses or difficult to use or understand. The type hints themselves are of dubious use. As a fan and advocate of static typing, I find myself advocating for type hints anyway, but I must agree I often can't reply anything to my coworkers' objections, because Python type hints are truly not that useful.
- wronglyprepaid 5y ago> The tooling that pays attention to type hints is slow as molasses or difficult to use or understand. I use mypy daily on big codebases, it is fine, not fast, but fine. > The type hints themselves are of dubious use. They tell you when you make type errors, they help you understand what type things should be. The same as in literally every other language with static typing. There is nothing special here, nothing different. python with a static type checker running in strict mode is not fundementally different from Java's static type checking. > As a fan and advocate of static typing, I find myself advocating for type hints anyway, but I must agree I often can't reply anything to my coworkers' objections, because Python type hints are truly not that useful. What do they lack that would make them useful?
- the_af 5y ago> The same as in literally every other language with static typing No, obviously not the same, otherwise I wouldn't be complaining. They are not even on par with Typescript, which I'm not a fan of either. > [type hints] tell you when you make type errors Not according to other comments I seem to be getting here. Other people are arguing type hints are not primarily for checking, but a form of notation for documentation. Seems wasteful, and I wish the Python community and tooling decided instead that they are for actually checking them. > What do they lack that would make them useful? Standardized, go-to tools that work in the build pipeline and that catch most errors without taking a long time to do so. I haven't found mypy to fill these requirements. It's so bad I cannot convince my coworkers to make the effort to write more type hints.
- hermitdev 5y agoPersonally, I took exception to the following from TFA: > Python is a dynamically typed language. By definition, you don’t know the real types of variables at runtime. This is a feature. In "you don’t know the real types of variables at runtime", this is just flat wrong. One doesn't know the real type of a variable until runtime. It seems to me the author maybe has a bit of confusion between weak typing and dynamic typing here.
- edgyquant 5y agoI get what they mean though. In a typed language you know the type of a variable at compile time. In dynamically typed languages there is nothing to enforce this and a variable can be passed with any type. So there wording may be off but the point stands.
- ModernMech 5y ago> "you don’t know the real types of variables at runtime", this is just flat wrong. One doesn't know the real type of a variable until runtime. I read the sentence as "you don't know the real types of variable at [the start of] runtime" as opposed to "you don't know the real types of variable *during* runtimes" So I understood the author to mean what you said. Could have been clearer you're right.
- School-Cotton 5y agoIn fact that quote is almost exactly the opposite of the truth. “Dynamic” literally means “at runtime”.
- tonyg 5y ago> One doesn't know the real type of a variable until runtime. In the program def x(f): return f(3) what is the "real type" of `f` at runtime; say, at the instant just before the call to `f`? How can you tell? If your answer is that `f` has type "function-like", then that's a much weaker kind of a type than even type hints offer, let alone a real type system.
- faho 5y ago
- theodorejb 5y ago> 1. If you're using a dynamic language, then _by definition_ the language will not enforce your static hints at runtime. Counterexample: PHP is a dynamic language which enforces static type declarations at runtime.
- ledauphin 5y agoMeh. you can do the same thing in Python if you really want - there are dynamic interpreter shims that can do this. The point is that it is not expected by definition, since by definition, static != runtime.
- lolinder 5y agoYou're assuming that type hints are by definition static-only. There's no particular reason why type hints can't be both statically and dynamically enforceable, as they are in PHP.
- dgb23 5y agoFun fact: it will still do type coercion in that scenario without strict mode. And you cannot annotate assignments. Otherwise it’s pretty useful.
- cardanome 5y ago> 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! So PHP is not a dynamically typed programming language according to you? It enforces type hints at runtime just fine. There is nothing in the definition of dynamically typed languages that says they can't use type hints to perform runtime checks.
- Jach 5y agoWas going to say the same for some implementations of Common Lisp, notably SBCL, which by default treats type declarations additionally as assertions. Subject to limitations it can use declared types and infer more types at compile time to produce more optimal assembly and give warnings if it detects type errors, or interestingly warnings if it has a chance to use e.g. a fast assembly add on a fixed sized int if you help narrow its inferred type with an explicit declaration one way or another. But unless it can prove a type always holds, it will also by default check declared types at runtime.
- mjn 5y ago> If you're using a dynamic language, then _by definition_ the language will not enforce your static hints at runtime. I don't think this follows by definition. It's common not to check the static hints at runtime, but a dynamic language could choose to treat them as contracts or assertions. Over in Lisp-land, SBCL will enforce static type declarations at runtime [1], contrary to most other Lisp compilers, at least under the default compilation settings (you can force it to skip the checks by compiling with a low "safety" level). If the compiler can prove that a static type declaration always holds, it will omit the runtime check; otherwise it will compile it into a runtime assertion. [1] http://www.sbcl.org/manual/#Declarations-as-Assertions http://www.sbcl.org/manual/#Declarations-as-Assertions
- grumpyprole 5y ago> can't fully represent heterogeneous values in a dict, given that you can't do this _at all_ in many statically compiled languages. This isn't really true. For example, in Java it's Map<K,Object>. For languages without subtyping, existential types are often used. It's quite common to see in infrastructural code, e.g. caching.