9 ms·
Static typing will not save us from broken software
- klodolph 10y agoI agree with the article. No silver bullets, just lots of regular bullets, and static typing is just another bullet. The main advantage for static typing from my experience are what happens when you have projects above 10kloc with multiple maintainers, and maybe the original devs have moved on to other teams. At that stage in a product's lifecycle, static typing reduces friction and covers some cases that are hard to test properly. Greenfield projects don't suffer from this problems for the first year or so. Refactoring is the major thing that's easier with static typing, IMO.
- xenadu02 10y agoAll tooling is much easier with static typing. Code completion, highlighting mistakes as you type... features that are much more powerful in a statically typed world. I agree though: it's a tool in the tool belt. It also varies dramatically across different languages and supported features which can make a huge difference in the kinds of problems it solves for you. Lately I've been doing a lot more modeling of problems with types when it makes sense... things like measurement units and their operators to ensure you can't accidentally add meters to watts. Or using unique ID types for each model so you can't accidentally create a reference with the wrong ID. The newer languages and updated standards (e.g. Swift, Rust, C++ with auto) take a lot of the useless repetition of types out of the equation and feel more like type annotations in a dynamic language. In the end I think we'll mostly settle on hybrids. Some will be static by default but support dynamism. Others will be dynamic by default but support static type annotations. What won't change is that you can't scale transistors below a single atom and we can see that endpoint on the roadmap. Performance improvements will not continue at the current rate. One could argue we're already there given the perf delta between CPU and memory or CPU and storage has gotten orders of magnitude worse. In a future where abstractions impose a real cost the optimization function may change, especially for established businesses and processes. Hiring a couple of Rust or Swift senior devs to rewrite your Python backend in a statically compiled language, then applying repeated optimizations might be worth the cost when you know it will be 10 years before a new CPU is released and it will be 10-20% faster at best. Or if you imagine future CPUs require exotic materials and 10x as much R&D to hit the same targets they become 10-100x as expensive.
- natec425 10y agoI've started to feel the same way. I feel like a lot of developers would be better off in a dynamically-typed language because it is such common practice to completely subvert the type system and there are such strong resources available for improving testing practices. My last job was in C#, and it seemed like so many things were stringly typed, entirely nullable, or used something else to weaken the type system. In addition to this failure to use the type systems, testing is becoming a much more rich environment. I think popular resources on effective testing are much better and numerous than popular resources on effective typing. There are great books and tools around helping developers test their software more thoroughly and efficiently. Comparing these testing resources with typing resources, the closest popular book I can think of for typing is Design Patterns, and I don't think most popular type systems are built with the program correctness as a top priority. I think rich type systems like haskell's will play more of a role in the future, and I think current users of these systems do experience a benefit. But if you have only ever done dynamically typed programming or used Java/C#, you are probably going to improve your correctness more over the next year by using a property based testing tool like propr (ruby), hypothesis (python), fscheck (.net), scalacheck (jvm), or jsverify (js), spec (clojure).
- DRMacIver 10y agoFWIW, rantly (https://github.com/abargnesi/rantly https://github.com/abargnesi/rantly) rather than propr seems to be the most active and usable Ruby property based testing library. (I maintain a list here: http://hypothesis.works/articles/quickcheck-in-every-language/ http://hypothesis.works/articles/quickcheck-in-every-languag...)
- natec425 10y agoAh. Thank you for the links. Also, thanks for hypothesis.
- LeonidasXIV 10y agoFor OCaml I'd argue that the canonical QuickCheck is https://github.com/vincent-hugot/iTeML https://github.com/vincent-hugot/iTeML (aka qtest). It looks like it is a unit test tool (which it also is), but it has merged in QCheck which I have used before.
- pixie_ 10y agoI spent 10 hours yesterday refactoring and adding features to a client side enterprise application that is well over 20k lines of TypeScript over tons of files. Yesterday was a pretty productive day for me. TypeScript easily caught hundreds of little errors as I coded and refactored which I fixed just a quickly. Most of the time when I tested my changes things just worked. I thought to myself every time TypeScript found something, 'wow I just avoiding another runtime error, thanks' Maybe people don't write or maintain client side software at scale. I don't know. But there's so little cost to having static typing I don't know why you wouldn't want it. I am easily an order of magnitude more productive with it. I code faster, my code works first time around more often, other people can understand my code easier, and my tests don't have to worry about validating types so they can be more logic oriented. There is zero chance anyone would of been able to be as productive as I was yesterday if that code base was dynamically typed. Not even close.
- d357r0y3r 10y agoThis is something I hear time and time again once a person has actually learned the technology (in this case, TypeScript) and seen the benefits in practice. For many pure front-end devs that have never really worked with static typing, the compiler just seems like another arbitrary build step in the pipeline with no discernible benefit.
- Someone 10y ago"…a client side enterprise application that is well over 20k lines of TypeScript over tons of files […] But there's so little cost to having static typing I don't know why you wouldn't want it" I don't think the OP would claim TypeScript is a bad idea, as, with its relatively weak type system, it doesn't really suffer from "if you find a bug it’s easy and unintrusive to add a test for it, but may require a substantial amount of work to refactor your code to add types that make the bug impossible". As an example of a strong type system, in Haskell code, the database access layer will may types such as "ISO-8859-1 string of at most ten characters" If it turns out that you want to store ISO-8859-2, changing that type can and often will cause a cascade of necessary changes, for example because you're calling a ISO-8859-1 to UTf-8 conversion function, and the compiler will not accept that call to now take a ISO-8859-2 string, or because you are concatenating that string with another ISO-8859-1 one. Then, you will have to decide whether to convert locally or whether to also change the type of that second string, etc. Now, of course, each of those compilation errors becomes a bug if you just use variable-sized byte arrays. Question is how much work you are willing to do to prevent those bugs.
- carsongross 10y agoBoth proponents and detractors of static typing seem to miss its major benefit: tooling. Being able to hit . and get a reliable list of things I can do is worth many millions of dollars to me.
- DRMacIver 10y ago> Being able to hit . and get a reliable list of things I can do is worth many millions of dollars to me. ...and mostly is possible because of the many millions of dollars that were thrown into developing it rather than the type system. Quality of tooling has much more to do with the amount of money invested in it than whether the language is statically typed. But this isn't a post about static vs dynamic typing as I said right at the top. It's a post about the effect of static typing on software quality.
- heinrich5991 10y agoCode completion is a fundamentally harder (if not impossible) problem with dynamically typed languages, as you might need whole-program and control flow analysis to even get the types of local variables. This fact has nothing to do with the money involved, it's probably rather another formulation of the halting problem.
- DRMacIver 10y ago> Code completion is a fundamentally harder (if not impossible) problem with dynamically typed languages Code completion tools originally came out of Smalltalk. It's relatively doable if you can attach to a running process that has dynamic access to your code. So that's "not necessary". It's also not sufficient: Most statically typed languages simply don't have this sort of tooling because it's very hard to write, and advanced type systems make it even harder.
- overgard 10y agoMost Smalltalks didn't really have great code completion (or code completion at all), and when they did, a lot of it had to do with the verbosity of method signatures removing a lot of ambiguity. Don't get me wrong, Smalltalk has some really cool features, but they did it by having a workflow completely different from static languages, and trying to imitate Smalltalk's environment in a language not designed from the ground up for it (ie, python or perl or whatnot) would be a lot harder. The fact that it's hard to write language tools in general doesn't change the fact that it's way harder to write an IDE for a dynamic language than it is for a static one.
- spankalee 10y ago> the idea that static typing will solve all our problems, or even one specific problem: The ubiquity of broken software Citation needed. Most proponents of static typing, myself includes, have much more modest claims: that is saves time spent by developers on smaller, more mundane errors. That it makes refactoring easier. That it allows for better IDE support like autocompletion and hover-over documentation. Even if these advantages are modest compared to fixing "broken software", they're still huge and worth the increasingly minor annoyances of modern static type systems, many times over.
- Veedrac 10y agoYou can argue on "most" advocates, but not "certain" advocates. Since you asked for a citation, how about the famous "Not relying on type safety is unethical"? https://twitter.com/queertypes/status/513510398570795008 https://twitter.com/queertypes/status/513510398570795008
- smarks 10y agoA digression on Java compiler performance: > Java's compile times are sorta reasonable but are apparently getting worse. I'm not entirely sure what this is about. Could it have anything to do with JEP 215? [1] There were some slowdowns in `javac` in Java 8, but these should be fixed in Java 9. Note this has more to do with type inference than with Java's type system per se, though this distinction is of little difference to most Java programmers. In our experience with OpenJDK builds, the main performance issues have been around redundant loading/parsing of library class files and JVM/JIT warmup time. These have mostly been mitigated by JEP 199. [2] With the exception of the issues I mentioned above, it's hard for me to see that static typing has had an impact on the performance of Java compilation. (Overall I agree with the main thrust of the article, particularly with regard to the "set of complicated trade-offs." Personally I find static typing very helpful, but it won't solve software quality problems.) [1] http://openjdk.java.net/jeps/215 http://openjdk.java.net/jeps/215 [2] http://openjdk.java.net/jeps/199 http://openjdk.java.net/jeps/199
- DRMacIver 10y agoIt might be based on false information - I'm a bit out of touch with Java development. I'll remove it.
- smarks 10y agoThanks for the update. Of course if there are any performance problems, I'm sure the javac team would like to hear about it, as this is something they do pay attention to.
- tome 10y ago> As static typing becomes more elaborate the scope of the bugs it can prevent becomes wider, but it usually comes with an additional cost: Build times. This is the meat of the entire argument, and it's false, as you can verify by running ghc with the -fno-code option. Type checking is extremely fast. It's everything else that's slow and that has absolutely nothing to do with static typing.
- wereHamster 10y ago> Software is broken because its not worth people’s while to write non-broken software This is the premise of a large part of the article. And it is wrong. At the very least a citation is needed. And even if there is a scientific source, I disagree with it. I'd argue that many people do want to write non-broken software, but they do not know how to efficiently use static type system, or they don't know how effective it is. If all you know is Java or C then of course you're going to doubt if a type system is worth at all. > As static typing becomes more elaborate the scope of the bugs it can prevent becomes wider, but it usually comes with an additional cost: Build times. I disagree. When you are working with Haskell, use ghcid and you'll have near instant recompile times. I made a proof-of-concept of a web frontend in Haskell, and it reloads with sub-second delay. That is comparable to a JavaScript project which uses webpack and babel.
- yogthos 10y agoYou can disagree what you like, but the fact that a lot of software out there has bugs and these bugs don't stop it from being successful clearly supports the point the article makes. If catching the types of bugs that static typing prevents resulted in reduced costs of software development, you'd see static typing out-compete dynamic typing. It's really that simple.
- tome 10y ago> If catching the types of bugs that static typing prevents resulted in reduced costs of software development, you'd see static typing out-compete dynamic typing Apart from network effects, inertia, lack of education and awareness, and all the other confounding factors.
- yogthos 10y agoThe complete and utter lack of empirical evidence with regards to purported benefits of static typing is the real elephant in the room here I think. Considering how long both disciplines have been around, you'd think we'd see some clear benefits by now. Yet, here we are swapping anecdotal evidence.
- notacoward 10y agoInteresting point about the relative value of typing vs. testing, and how too-strict typing can crowd out testing. However, see the discussion under pixie_'s comment about new code vs. refactoring. Also, this makes me think about incorporating testing directly into the language, which kind of brings us to Design By Contract and formal methods. It seems to me that now would be a good time to resume active research on those things, instead of all these exhortations to use magic type systems and magic immutability and so on.
- je42 10y ago> I’d expect static typing to win out for correctness if: [...] very large. I would disagree. In very large projects, strong types don't scale very well across repositories / deployable units. A very large single repository, it may be ok. Except that refactoring types will like break a lot of in-flight pull requests and branches.
- solatic 10y agoOP's argument, boiled down, is the following: 1) Behavior needs to be automatically checked 2) To check behavior, you can either write tests or specify types 3) Tests are more flexible than the type systems of popular languages (e.g. to write end-to-end tests) 4) Testing purely dynamic languages is quicker than compiling statically typed code 5) So prefer tests to type systems because agility Honestly this is a load of bollocks and I'll explain why: * When business execs throw out the old UI (old end-to-end tests) and replace it with a new UI (new end-to-end tests) and your new tests are failing because undefined, well, have fun and good luck! * The longer a system lives, the longer the test suite gets. So no, your developers are not going to be running the entire test suite at their desks, even if at the beginning of that project, running that test suite took all of half of a second. This is one of the reasons for continuous integration servers, actually, so that the massive test suite can be parallelized across a bunch of build slaves and run overnight while the programmer is at home or working on a different feature/problem. And then the difference in compile and start-up times is psychologically irrelevant because the programmer will still think "ok, I submitted the build to CI, time to go home/work on something else". * Good type systems, combined with proper IDE support and proper object-oriented design, do optimize for deletion by reducing the number of places in a codebase in which refactoring has an impact. It is incorrect to state that type refactoring should be some kind of massive refactoring affecting every file in the codebase every time you refactor. A refactor should either eliminate a given subtype, thus leaving the other subtypes unaffected, or add a subtype, where no-longer-common code/behavior can be factored into a new intermediate type. When the supertype needs to be changed, well, you still need to test those changes, but at least you only needed to make the change in one place, and not an indeterminate number of copy/pasted places in dynamically typed code which, you know, good luck finding them all. Static typing is a practical requirement for long-lived, large systems. OP makes way too many assumptions on the basis of small, short-lived projects.
- clusmore 10y agoI watched a talk by Erik Meijer [1] recently where he mentioned that an implementation of a tuple such as (C# syntax mine, but illustrates the point) class Tuple<T1, T2> { public Tuple(T1 t1, T2 t2) { } public T1 Item1 => default(T1); // null for reference-types public T2 Item2 => default(T2); // null for reference-types } is a perfectly type-safe implementation of a tuple that's completely nonsense. I'm curious as to how you might actually encode into the type system that the values that come out of Item1 and Item2 are actually the values you put in. I would love to see tests at the interface level (or typeclass level for Haskellers) rather than the implementation level, to enforce that all implementations of an interface satisfy laws like this. In Haskell, this would mean that you could enforce things like monadic laws which we all assume to be true anyway. [1] https://www.youtube.com/watch?v=JMP6gI5mLHc https://www.youtube.com/watch?v=JMP6gI5mLHc
- dllthomas 10y agoIf you require a constraint to be able to provide Default values (even if every type in fact implements Default - c.f. Typeable) then for Tuple in particular there is only the correct implementation (modulo bottom or hidden side-effects).