8 ms·
I've seen a lot of push back on adding type checking to Python but we had a similar case at my company where we tried it out on a new project and the clarity an
by gundamdoubleO 5y ago
I've seen a lot of push back on adding type checking to Python but we had a similar case at my company where we tried it out on a new project and the clarity and readability of the code was immediately beneficial to the entire team. Perhaps it's something well suited to larger codebases.
- hobs 5y agoI think it's well suited to anything really - the amount of casual problem solving and inference you can make from some simple types is pretty big in my experience, and Python's approach to allow you optionally buy into it is really nice.
- tester756 5y agoIt's $current_year and there's still debate whether checking stuff at compilation time is better than at runtime?
- novok 5y agoPeople who don't think types are a good thing need to work in a statically typed language for a year or two and then see what a difference it makes in reality. Unproductive Java bureaucracy != static typing. I think the people debating it never tried it seriously.
- fiddlerwoaroof 5y agoI’ve done everything from Haskell to Java and I still strongly prefer Clojure and Common Lisp-style dynamic types.
- lemper 5y agoi have a small side project in clojure [1] and i always miss type checking when working on it. not by much because it's a small project but i am tired of iseq is not a function error. [1] https://dactyl.siskam.link https://dactyl.siskam.link
- fiddlerwoaroof 5y agoI sort of think there are two mindsets behind this debate: people that miss the guard rails of a static type system and people that enjoy the experience of iterating quickly in a dynamically typed language. I don't really want to say everyone should pick one side or the other, just that my experience doesn't bear out the claim that "statically typed languages produce more maintainable code". And, the little bit of empirical evidence for this proposition is largely inconclusive: https://danluu.com/empirical-pl/ https://danluu.com/empirical-pl/
- simion314 5y ago>and people that enjoy the experience of iterating quickly in a dynamically typed language Programmers spend more time reading code then writing it. So I personally prefer the devs in the team will spend more time typing the code or use a bit more brain energy to think about types so later we can all read the code and understand it and edit faster. Dynamic works great for write-only scripts.
- fiddlerwoaroof 5y agoPeople always say this about reading code and it’s just never matched my experience working in either sort of codebase: one difference (comparing lisps and, say, Typescript or Java) is that lisps just have fewer lines to read. So, any assistance you get from the types is counteracted by having to read more code. But, additionally, I just don’t find it true to my experience that it’s easier to read and understand a dynamically typed codebase vs. a statically typed one. Especially when you have a lisp-like environment that makes accurate jump-to-definition possible. EDIT: I think I just tend to think about codebases in terms of operations rather than types. And, consequently, when I build a codebase around compositions of functions, the way I think about it isn’t very different in either paradigm.
- simion314 5y agoMaybe it depends on what you work on. From my experience things go like this 1 we have a simple problem I implement a simple elegant solution 2 some new feature is added, this means there are some special cases now, most of the time someone else in the team adds this new feature , so 4-5 different places are modified, functions need to get more parameters and some IFs are added in those 4-5 places 3 later a new feature is added again, a few more extra special cases again , the dev will again go add some more function parameters here and there , add more IFs but fails to find where all the places that might need to be modified are. 4 things are now a big mess, I have to fix it, and I now have to read all the code, my own old code that was changed with different exceptions and the other developers code. I spend a lot of time on reading stuff, understanding how stuff works now, understand why this new code does some stuff then I spend the time abstracting again a solution, abstracting all the special cases. After I have a solution in mind comes the refactoring, with static types or type hints is much easier to find where stuff is used so you know what to modify. I am sure one some projects where maybe there is only 1 or few devs that all write quality code and there are no new requirements that need implemented ASAP the code could stay more readable but this is the exception unfortunately.
- arwhatever 5y agoIs it possible to elaborate in a comment? Honestly I probably wouldn’t take the time to read a lengthy article, but if there’s some elevator pitch then I’m all ears.
- fiddlerwoaroof 5y agoWhat makes CL/Clojure really work is that your editor (emacs usually, but there’s other options now) connects to the live program and has access to the entire runtime environment. So, you can do a lot of the things other languages need static types for via introspection (e.g. autocomplete: CL just asks the running program what functions are available that matches the current pattern and returns a list). Secondly, since I’ve learned statically typed languages, I already have a mental model for how they make you structure your code, except dynamically typed languages make patterns easy that would require something like dependent types to check (see how complicated Typescript is, because it has to be able to model JS idioms). My experience is that a lot of the value of static types isn’t in the checking but in the modeling aspect: if you follow the general patterns you’d use in Haskell (represent algorithms like “apply a function to each member of the list” as functions), you reduce the amount of thought it takes to see the program is correct by splitting it up. For example, if I have this pattern in my imperative codebase: let result = [] for (let idx = 0; idx <= input.length; idx++) { result.push(input[idx]+1); } return result I have at least three things mixed up together: accessing each member of a list (and there's an easy to miss off-by-one error in this implementation), transforming that member and building up a result. If I translate this to a functional style, it's easier to see that the implementation is correct: const inc = v => v+1 . . . return list.map(inc) Looking at this code, I can break down correctness into three questions: is list.map implemented correctly? is inc (the transformation) implemented correctly? And, assuming both are correct, are these two functions combined in the correct way? Types definitely can help here but my experience is that 90% of the benefit isn't the _checking_, it's the code structure you end up with as a result.[1] Now, if this is true, why do I prefer dynamically typed languages? Well, it comes down to two things: I find the "live programming" model of CL/Clojure more productive and roughly equal to types when it comes to checking correctness (and I don't think it's just me, I've seen various papers, etc. that claim Haskell and Clojure have roughly equal defect rates); and, I find the patterns I like in CL/Clojure/Javascript require much more sophisticated type checkers to actually validate, and such type-checkers have a huge up-front learning cost and still add a lot of boilerplate that exists mainly to convince the type-checker that you know what you're doing. Finally, in a language with macros, you can roll your own static guarantees: one project I worked on was doing a bunch of calculations inside a database. We hit an edge case where the DB's idea of a week didn't match our requirements. As a result, I wrote a code generator that generated Clojure functions and DB queries simultaneously. In this situation, if you assume the code generator is correct, you have a compile-time guarantee that the Clojure versions of the queries are equivalent to the calculations being done inside the DB. [1]: This page surveys a bunch of studies on the question of dynamic v. static types and finds the evidence in favor of static types to be surprisingly small https://danluu.com/empirical-pl/ https://danluu.com/empirical-pl/
- JoelMcCracken 5y agoI'm curious, after having done a significant amount of Haskell, I have flipped that opinion. The biggest difference is how the types help make things explicit and clear. (although, IMO, I think purity makes a very large impact here too)
- jfabre 5y agoI have to agree, I've done over 5 years of C# and then went to ruby and never looked back. Static type checking raises the floor on incompetence, but also lowers the ceiling on excellence. I have to admit I don't have experience with the extremes which would be Haskell and Clojure. The amount of cruft I had to type in C# just to get shit done... It's all implicit in ruby thank god for that. I never EVER have to check the type of a variable at runtime. I always know its type just by looking at its name. Is it enforced in ruby? Of course not. Ruby assumes I'm an adult and I know that I'm doing.
- handrous 5y ago> I always know its type just by looking at its name. Is it enforced in ruby? Of course not. Ruby assumes I'm an adult and I know that I'm doing. TIL taking notes of things you want to be reminded of in the future is for children and the incompetent.
- malfist 5y agoHow in the world does type checking lower the ceiling on excellence?
- cle 5y agoI"m guessing by rejecting perfectly valid and correct programs that are unable to be type checked. There is a large space of "false negative" programs that a type checker will reject, but that could be perfectly correct. E.g. compare Python-esque duck typing with nominal typing.
- novok 5y agoYou can have that by using Any as your type if you so wish typically and escape the type system for those rare circumstances. Also C# suffers a similar issue with what I call "unproductive Java bureaucracy", since it's basically Microsoft Java. Bureaucracy is not static typing. You can also have full dynamic dispatch and still have static typing too.
- deleted 5y ago
- Akronymus 5y agoLISPS are the only languages where I feel like dynamic typing works well.
- jonny_eh 5y agoAfter using TypeScript for even a little bit I find it painful to go back to JavaScript for anything more complex than white-boarding.
- wvenable 5y agoA lot of people grew up with Java -- especially early Java -- as their primary language. It was taught heavily in schools. I think it ruined a lot of people to static typing and exceptions because Java is/was terrible for both of those things.
- kzrdude 5y agoThat's not really the debate in Python :) Almost every Python user now has to "deal" with type annotations. It's tempting to gradually add type annotations, it's nice documentation. But it also rubs me the wrong way to have annotations that are never checked(!). In many codebases, you might just have "casual" style type annotations in Python, and nothing ever asserts that they hold. That's nagging on me, a bit.
- inertiatic 5y agoNever checked? They're statically checked. Also, tooling like https://pydantic-docs.helpmanual.io/ https://pydantic-docs.helpmanual.io/ can do runtime checking for important parts of your app or you can use this https://github.com/agronholm/typeguard https://github.com/agronholm/typeguard to enforce all types at runtime (although I haven't measured the performance impact, probably something to do in a separate environment than production?).
- kzrdude 5y agoThey are statically checked, if you run a type checker. Which many don't.
- tehnub 5y agoThat's a good point. If they're never checked, then they're just like incorrect/outdated comments. They sort of get at this idea in the article, and sort of describe a compromise for it. They have a list of files that they've completely annotated, and only those files are checked by mypy. So in their case, they know which annotations to ignore, and which they can rely on.
- deleted 5y ago[deleted]
- handrous 5y agoI want type checking on pretty much anything that will ever exceed about two screenfuls of code. If I can't keep the whole thing in my head at once, I want the computer to do it for me. That's the point, right? Making computers do stuff for us so we don't have to?
- david422 5y agoI kindof think of them as a giant set of unit tests. The compiler/linter etc. can check every variable and every function call to check to make sure you didn't mix up your types, which _will_ blow up at runtime if you got them wrong. So rather than write them all by hand, just get your tools to do it.
- handrous 5y agoI see them as documentation of what I think something means or is, which the computer can check for accuracy (more or less), both as I write and as the codebase changes. That legibility to the computer is what makes them much better than documenting the same thing some other way. Are they out of date? Were they wrong to begin with? The computer will tell me, no action needed on my part. I need to look up something in the context of what I'm reading right now—oh, look, the computer just told me exactly what I needed.
- matsemann 5y agoJust wish Python's typing was better. But it's impossible to type hint the crazy "pythonic" code out there. Like the kwargs used to do a Django query.