6 ms·
I code without types. My "proof", that types do not pay for themselves goes like this: Every time I encounter a bug (during coding, testing or in production) I
by TooCreative 6y ago
I code without types. My "proof", that types do not pay for themselves goes like this:
Every time I encounter a bug (during coding, testing or in production) I make a note what type of bug it was and how it could have been prevented.
Types are way down on the list of what could have prevented the bug. Especially for production bugs, which are the most important of course. It is so rare, that a bug could have prevented by types that I can say with confidence that they would have been a net negative.
Talking about which tool can prevent the most bugs, integration tests win by a large margin.
The reason is that most bugs are conceptual. Like "Oh shit! We have allowed people to tag items as duplicates of other items. And we have a function that traverses the list up to the original item. But now this new feature over there had a bug where it marks the last original as a duplicate of another duplicate and then when the traversal function in that other module is used, it ends up in an infinite loop".
Another example of a popular bug category: The code contains assumptions about the environment that do not hold true. For example PHP's mb_strtolower() will not always create the same string as MySQL's LOWER(). It is very rare and only holds true for a tiny tiny fraction of the UTF-8 characters. So you might expect them to behave the same until you one day trip over one of those few chars.
- viraptor 6y agoCan you share the tally? I wonder about the categories you used.
- AaronFriel 6y agoGiven that you don't code with types, how are you certain which bugs you could have prevented? I'd be curious to see this list. Is it anecdote, anecdata, or is it a spreadsheet you have somewhere?
- benjiweber 6y agoI find the value of static typing to be more from increasing the ease of exploration and understanding of a codebase than preventing bugs directly. The constraints on how the code you're reading could be being used making building a mental model faster. Not to mention the tooling built on top of the typing that can help with exploration.
- Twisol 6y agoIt's interesting that you talk about bugs, when the OP doesn't make that argument. The OP is very clear, actually: > It didn't mean I was free from logic bugs. (Nothing can do that in the general case!) It did mean that a program which type-checked wouldn't blow up in ways the type-checker said it shouldn't, though. Other than soundness (which is not the same as avoiding logic bugs, anyway), the points the OP raises are about expressiveness. Types help [you / the OP] organize more of your knowledge in the codebase. That's never going to be the most obvious preventative measure against bugs, because the goal is higher-order: structuring your codebase so you can reason more clearly about the program.
- TooCreative 6y agoThat might be a matter of personal taste. How ones brain is wired. For me, types make code less expressive. I can grasp the structure of a piece of code the easier, the less meta data there is on top of the algorithmic structure.
- tluyben2 6y agoWhat are you working on though? What algorithmic structure?
- TooCreative 6y agoCompare this: private static function request(?string $method, ?string $url, array $options): array { ... } To this: function request($method, $url, $options) { ... } I can grasp the latter much better. It immediately forms a structure in my head that I will remember while I read other parts of the code. To do the same with the former, I think my brain uses up twice the energy or more. And even then, I will not have such a good grasp on it as with the former.
- unrealhoang 6y agoCounter point: with the former, I know exactly how to use it: for item in request(“get”, “google.com”, []) { .... } Whereas if there’s no example for the latter, I’d have to read the code of that function (or sometime the code of the functions it called) to know how to use correctly.
- deleted 6y ago[deleted]
- simion314 6y agoMaybe your style is not fit for types? So I fixed a bug recently where a url validatior code was falling because the code was old and recently what is allowed in an url changed. Imagine there was a language where url/email/file path was a type that could validate itself when you create it and you don't need to always try to create regex to validate things. Even more cool would be if string would not be something we use daily (like we don't use every day bytes) so we would have always a type for customer name, file name or file path and you would need to explicitly ask a conversion from a customer name to a file name etc. The way I think future languages and types could help is to make it almost impossible co create invalid data structures or state.
- tluyben2 6y agoI think it takes people who do not start out 'believing in types' (I was taught by pupils of dijkstra in NL so my belief in strict-as-possible has always been quite firm) a same kind of timespan / experience as the OP; experience (very) large weak/stringy typed projects, experience them for at least a few years full time and then, when the frustration sets in, try something which is the complete opposite like Haskell/Rust. I think a certain frustration needs to be there to try something else anyway, when you come against the billionth cannot call hello() on undefined error in a critical (for the company), 100k+ LoC, multi-team project, you might wonder if there is something else. You are probably not going to post your 'list' here but proper types prevent many trivial and non trivial bugs. Many of the points on your list will fit there, but you wouldn't know it yet. > Talking about which tool can prevent the most bugs, integration tests win by a large margin. Obviously there are ways of catching them without types, but proper type systems catch them at compile time and also; how are these mutually exclusive; we use both. We just need less integration tests. > Like "Ooooooh shit! We have allowed people to tag items as duplicates of other items. And we have a function that traverses the list up to the original item. But now this new feature over there had a bug where it marks the last original as a duplicate of another duplicate and then when the traversal function in that other module is used, it ends up in an infinite loop". In some of my favorite languages you can catch this in types at compile time. Obviously; do what works best for you and your team; I just don't buy your overarching statements and 'proofs'. If it works it works, but it would probably work better with types.
- kybernetikos 6y agoWorking on a large scala codebase, I quickly learnt that 'compile time' in one language does not always happen before 'run time' in another language. What matters is not the phase in which the bug is found but how close in absolute time finding the big is to writing it.
- tluyben2 6y agoAgreed and we have to continue improving in every way; dynamic/static/hybrid, just saying that I have not seen this dynamic enlightenment in larger projects. I have only seen the pain of runtime errors that other (static language) teams never had. Sure, if you would-have-written a test for it, you wouldn't have had it either, but types rather force you to think about it while writing. So sure, you are 'done faster', but the fall-out, and again ofcourse YMMV, of having statically preventable bugs popping up in Sentry at 3 am in the morning with things you would've prevented (not necessarily directly by the types but you would've thought about it more because you had to define the types, which is I think what the parent poster here misses too; I just tend to think less and try more without types which, again for me, is a bad state, but ymmv) is not great. But sure, I am biased as my experience with statically typed langs has been good since I moved from asm/basic in the 80s to pascal/c (they were an improvement over asm/basic and my first experience with types, not saying you should use them now, or not).
- NicoJuicy 6y agoI have the feeling you are applying your experience from coding your own project. And not from a project in a team, where you didn't code everything.
- petters 6y agoIMO types in Python mostly pay for themselves when you develop in a team. They greatly improve the developer experience by providing automatically enforced documentation. Allows IDEs to provide code completions etc.
- deleted 6y ago[deleted]
- lgas 6y agoI moved (very roughly) from Java to Python to Haskell. When I was coding in Python if you asked me what percentage of bugs I encountered could have been caught by types, I would've probably said about 10%. Because I would've been thinking about types in Java and errors like calling "length" or a string and then accidentally calling "length" again on that int value from the previous call to length. Now that I am working primarily in Haskell if you ask me the same question I would say probably about 90%. Not only does catching the "calling length on an int" types of errors at compile time but it gives you whole new tools (newtypes, Sum types, mtl-style constraints) for expressing complex concepts in a simple manner in the type system. And all of these tools result in having to spend much less time thinking about things I had to think about in python, leaving me to spend more time thinking about the business logic which reduces the number of logical errors (which obviously can still occur). As a concrete example I transliterated some Python code that someone was asking about on reddit into Haskell here: https://gist.github.com/lgastako/f7465339214c6fde0fd75f4e488b447a https://gist.github.com/lgastako/f7465339214c6fde0fd75f4e488... You can see on line 57 "unless (status == Fresh) $ do" -- I originally wrote checkStatus as a function that returned a boolean and the expression was "unless fresh $ do" but I replaced the boolean with a tri-valued sum type and rewrote the check against the value "Fresh" -- this avoids the boolean blindness problem and makes it much harder to get the condition wrong -- and while it's still possible to get the condition wrong, it's much easier to find it when you do.
- SPBS 6y agoIt's not just about preventing bugs. Types restrict what you can do with each variable, such as what methods/members exist on the variable and what valid operations you can do with it. It makes development easier because you don't have to hold it all in your head. Every member/method access is validated at compile time, without needing to write any tests. You may not make such mistakes when writing dynamically typed code, but if you ever need to change something (like the name or type of a variable/method/member) it inevitably means trawling through all references in your codebase manually and changing them by hand. Please correct me if there's a better way to do it in dynamically typed languages.