39 ms·
Diminishing returns of static typing
- 201709User 9y agoIf I don't have to maintain the thing you can give me any Python, JS or Go you want!
- cm2187 9y agoThe benefit of static typing isn't just reliability. Tooling is another major argument. Won't appeal to certain hardcore programmers who think that even notepad has too many features. But it is great for refactoring, finding all references to a function or a property or navigating through the code at design time. Basically all the features visual studio excels at for .net languages. And I disagree with the barrier to entry argument. Static typing, by enabling rich tooling, helps a beginner (like it helped me) a lot more by giving live feedback on your code, telling you immediately where you have a problem and why, telling you through a drop down what other options are available from there, etc. Basically makes the language way more self-discoverable than having to RTFM to figure out what you can do on a class.
- taeric 9y agoLive coding environments are amazing at this, as well. Often without the need for as extensive static typing, since it can just use reflection. This isn't to say that static typing isn't good at this. Just, even with that, there is a lot of effort that goes into making the rich tooling. A lot of very smart and capable folks work hard to make Visual Studio.
- fulafel 9y agoDynamic languages support this kind of tooling too - you can even have seamless data completion (eg. map/dictionary keys). The original Refactoring Browser was written for Smalltalk. Etc. Of course there are cases where dynamic languages do worse, but it balances out I think.
- cm2187 9y agoBut how can you offer any refactoring or auto-complete inside a function if you don't know what type to expect as an argument?
- fulafel 9y agoIn dynamic languages functions aren't typically overloaded by argument type. For OO languages and methods it does get a little guesswork-y, and tools often offer a wider range of guesses than is correct for completion. But you can show the class along with the offered completion, so it's not too bad.
- actsasbuffoon 9y agoYou can, but you may start to run into some limitations. Many languages have some version of type inference, which allows them to figure out the type of a thing, even though the programmer didn’t specify it. C# has a very weak version of this with the auto keyword. Languages like Crystal take it much further by tracing the flow of data through the entire program. It generally works quite well, though there are a few edgecases that require explicit type annotations. As for auto-completion, some languages feature designs that make it easy to offer auto completion even without type information. For instance, Elixir doesn’t have methods. You only have functions defined on modules, and it’s trivially easy to know what functions are defined on a module. So it’s possible, but there are some limitations.
- TheDong 9y agoType inference goes hand-in-hand with static typing. Those are not opposite things. > C# .... Crystal Both are fully statically typed languages with type inference. Those are unrelated to the argument the parent comment is making.
- jaggederest 9y agoThey still both allow generic arguments, in reduction, this means that they still have uncertainty. I can and have built a totally untyped language within a fully statically typed language - nostrademons' Scheme-in-haskell exercise is a lot of fun. You just have to define a Universal type and then back out of all that nasty compile-time nonsense. Everything is Univ and Univ is everything.
- cle 9y agoIMO the autocomplete argument is rather unconvincing. Every dynamic language I've worked deeply with has powerful and simple introspection capabilities, and they generally come with much more interactive development environments (shell/REPL), so I've never found API discoverability to be any worse than statically typed languages, just different. In general though, the more you can formally reason about the program, the more you can automate program transformations (refactoring). Programmers in dynamic languages will argue that the amount of code is far less than the equivalent code in a mainstream statically-typed language, so while the cost of refactoring may be higher per unit, the number of units is less, so the overall cost is the same (or less). I believe in using the best tool for the job...some use cases would benefit more from static typing, while others would benefit more from using a dynamic language. One of the most important factors is the team and its engineers' backgrounds, preferences, styles, etc.
- wootness 9y agoI found Ruby (even in something like RubyMine) to be a far cry from even the basic stuff you get from Java. Suggestions for vars and funcs that don't actually exist really slowed down things.
- emodendroket 9y agoDoes anyone believe in using the wrong tool for the job?
- disconnected 9y ago> Does anyone believe in using the wrong tool for the job? Yes. PHP developers. :)
- cle 9y agoYes! Many engineers use tools they like for reasons unrelated to the job they're doing or the product they're building.
- emodendroket 9y ago
- ruskimalooski 9y agoAgreed. Although other comments claim that their dynamically typed languages have this same property, inherently in dynamic languages the auto complete will fail out unless you effective write code as if you were using static types.
- christopheml 9y agoMy main progamming language at the time is Java, and the amount of assistance my IDE provides is astonishing (to the surprise of no one, it's IntelliJ). The confidence strong automatic refactors provide is of great help when managing large codebases.
- amirouche 9y agoI agree that static typing helps reading comprehension and that IDEs like pycharm help getting into big code bases, that said, at the end of the day, when you know the code both the IDE and static typing are getting in the way. Actually, I never saw anybody as quick as people using simple editors like emacs and vim. GUI is getting in the way of the programmers intent. Static typing is a hindrance in front of refactoring. Unit tests is the only truth that matters, static typing or not.
- always_good 9y agoYou're kinda damning it with faint praise when you say that you can use dynamically typed languages on small projects that fit in your head (and are also probably written by a single developer). You can pretty much use any language in that scenario. But the chickens come to roost around day 30+ or so.
- icebraining 9y agoA large project is a poorly decoupled set of small projects.
- orthecreedence 9y agoTrue, once my libraries get bigger than five or six assembly instructions, I tend to break them down to a more manageable size.
- always_good 9y agoMay be. Meanwhile real-world non-trivial projects tend to be large projects. Nice to be prepared for that instead of gambling on "surely we'll extract out smaller projects that fall on the right abstraction boundaries in the face of unknown future requirements."
- drblast 9y agoDefinitely. Static typing lets you turn the compiler into a hard-working friend that helps you refactor large projects without going insane. There are no diminishing returns. Defining types is easy and enhances code readability.
- cle 9y agoBelieving that any technology has no cost is poor engineering IMO. There are costs to that rigidity, and they're rather self-evident.
- cobbzilla 9y agoNo one is saying there is no cost. The cost of using static types is (1) you have to think about type info when writing the code and (2) you have to fix compile-time type errors while you are developing. The poster is claiming that, over time, as code bases tend to grow large, this small investment yields increasing (not diminishing) returns; a claim I would agree with.
- ridiculous_fish 9y agoIf you believe there are no diminishing returns, I'm interested to hear your reply to the author's question about why we don't all use Agda or Idris.
- Arcsech 9y agoWell, the easy answer is that dependently-typed languages like Agda and Idris aren't very mature yet. They're still missing many commonly-needed libraries, compile times are slow, the tooling isn't great, etc etc. Getting a language to the point where it's workable for serious projects is a lot of work. Rust is getting there with the backing of Mozilla, Haskell has made some decent strides too (but still has a way to go, and I think has some pretty fundamental flaws entirely apart from the type system). It'll be probably another decade at least before we see any dependently-typed languages getting a serious foothold, but I do think they're going to become a lot more common eventually.
- gnaritas 9y agoI can do all of those things in Smalltalk, which is dynamically typed; these things are not byproducts of static typing, they're simply byproducts of mature tools. So no, these are not arguments in favor of static types.
- igouy 9y ago>> finding all references to a function << Yes, you can find all references to a method in Smalltalk -- but those references are not separated-out from all the references to other methods that happen to have the same method name but are defined on a different class. With type information for the receiver and method arguments, we can find just the references we're looking for.
- lispm 9y agoI can ask my Lisp IDE to find callers for methods based on the sub/class of arguments.
- igouy 9y agoDoes it work better if you use type-specifiers in your code :-)
- KingMob 9y agoI can't speak to Smalltalk, but any namespaced Lisp system can figure out what references what. The key is that the searches happen through the REPL, not grep/ag. So if I tell CIDER to find all instances of a Clojure symbol, it can use the namespace to avoid false positives.
- igouy 9y agoAre you saying that reduces the number of false positives or are you saying that eliminates false positives?
- 9y ago
- Eridrus 9y agoI think dynamic typing proponents get hung up on the auto-complete aspect. The real benefit is when you find someone writing a property with a common-ish name to a data structure and you want to know "who the hell uses this", you can answer that question pretty easy in statically typed languages. In dynamically typed languages you kind of just grep and hope the name is not too common.
- Eire_Banshee 9y agoThis. Not just, "who the hell uses this", but "where the hell is this defined" as well.
- flavio81 9y ago>Not just, "who the hell uses this", but "where the hell is this defined" as well. On Common Lisp, a dynamic language, I can also get this answered instantly. I just press a key combination on a method call and i jump to the definition. So this isn't exclusive to statically typed languages.
- Eire_Banshee 9y agoLets be real, when we say dynamic languages, we aren't talking about niche languages like Lisp. We are talking about JS and Python almost exclusively.
- amirouche 9y agoPython has jump to definition too.
- adamnemecek 9y agoYou mean there’s an ide with that feature? It’s never as good as with any statically type language.
- 9y ago
- 19873287234 9y ago>Tooling is another major argument. vscode seems to figure out the types in javascript without any static typing. >But it is great for refactoring Searching for strings isn't that much worse. Also, when it comes to web development, you cross into the client-side and suddenly you can't refactor. So you can only refactor the server-side and end up with a mismatch. >finding all references to a function or a property or navigating through the code at design time You can do that without static typing in many cases as well. >Basically all the features visual studio excels at for .net languages. When I was working in c# on the server and javascript on the client, I really hated having to go back into c#. >telling you through a drop down what other options are available from there vscode seems to be able to figure this out most of the time as well. I think static typing is necessary when you need performance because all of the fast languages are statically typed. I think a lot of these things are about organisational complexity and making sure new and average programmers don't screw up the software. It is about large companies trying to manage their organisation, it isn't about the complexity of the code itself. There are a ridiculous amount of tech companies that have used dynamic languages to go from nothing to the biggest companies in the world and only switched to static languages well and truly after that occurred.
- cwyers 9y ago> vscode seems to figure out the types in javascript without any static typing. Doesn't it do this by treating Javascript as a statically-typed language (Typescript) and using type inference?
- 19873287234 9y agoNo it works without using typescript. I just figures it out through... I have never thought about it. I mean, var p = new Cat();. I am sure it can find the cat definition easy and read the properties and so on. It probably can't prove things 100% but it can guess very well at what things are.
- FLUX-YOU 9y ago>I just figures it out through... I have never thought about it. Are there not definitions written by someone or a tool that vscode looks at? That is what I saw using some npm packages with typescript: http://definitelytyped.org/ http://definitelytyped.org/
- DavidWoof 9y agoIf Visual Studio is your example, then you're making the same argument as the author: there's a sweet spot. From the python world, c# may look statically typed, but from the Haskell/Idris point of view, the java/c# type systems look really sloppy and ambiguous.
- macspoofing 9y agoI'm so happy to see the pendulum swing the other way, because when JavaScript was becoming popular, and Ruby and Python had a popularity renaissance (around mid to late 2000s), I had a lot of online arguments about the value of static typing. People were complaining about static typing for the dumbest reasons (it's too 'wordy'). It started as a backlash against old-school enterprise Java development (which was fair, EJB2 world sucked) but then it went completely off-the-rails. Typing in Java could be better, sure, but even with its quirks it's way better than the nothing you get with dynamic languages. There are a class of bugs you just never need to worry about when the compiler does some compile-time checks for you ... like worrying that you passed the wrong type into a function, or the wrong number of arguments. Thank God people are coming to their senses.
- wiremine 9y ago> EJB2.0 world sucked This is the #1 reason I leaned away from static typing. Typescript and Swift have changed my mind. I now see typing as a helpful tool that can solve a lot of problems.
- enraged_camel 9y ago>>There are a class of bugs you just never need to worry about when the compiler does some compile-time checks for you ... like worrying that you passed the wrong type into a function, or the wrong number of arguments. People always say this and it baffles me. Bugs like that should be caught immediately by your test cases. You shouldn't rely on the compiler to catch them for you.
- 201709User 9y agoYes, why do something automatically when you can do manual work!
- icebraining 9y agoI think the idea is that you have to write tests anyway.
- sacado2 9y agoThere's not only tooling and reliability. Don't forget performance, too. Knowing at runtime that a memory word represents, for instance, an integer rather than a reference to a struct that contains both a type tag and a reference to the actual value, makes a huge difference. And I'm not even mentioning the inlining possibilities.
- walshemj 9y agoAlso the article does not take into account the much higher cost fixing a bug in live compared to development
- Merovius 9y agoIt does (though admittedly not very explicitly), it just rolls it into the "benefit" (i.e. not shipping broken code is a benefit) and the "weight given to stability". If a bug discovered in prod (or even qa/canary) has a significantly higher cost than a bug discovered early, that will influence the weight you are putting on stability. In that way, this factor is subsumed in one of the other graphs. As you might've noticed, I have been intentionally light on the details and only talked pretty abstractly about the specific scales and factors involved.
- walshemj 9y agoTy I take the point and it depends on the sort of project your working on a celphone app is different to say a major telcos billing system.
- gwbas1c 9y agoIsn't static typing a requirement when writing an algorithm and data structures for "every bit and clock cycle counts" situations? How can a 0-compute overhead for dynamic typing exist in a dynamic typed environment? I always thought dynamic typing is a feature for situations where the code needs an extreme amount of flexibility to adapt to a wide variety of data; even at the expense of performance.
- bjz_ 9y agoA good static type system will give you the ability to be able to control the level of dynamism in various parts of you code. For example you could create tagged unions to create mini dynamic type systems within parts of your codebase.
- tonyg 9y agoNot unless you think assembly language or machine code are statically typed.
- naasking 9y agoAssembly is typed. The types are machine words and usually floating point types are also available. Basically, the machine types are the types of data that the register files can hold.
- tonyg 9y agoYep. You can, of course, make a similar argument for Scheme. But you don't get a very interesting type system out of it. Perhaps I should have written "... nontrivially statically typed."
- naasking 9y agoSure, but to bring it back to the original question, the fact that you can trivially distinguish floating point from word types already means statically typed languages are easier to optimize than dynamically typed languages for numerical programs. And there are all sorts of optimizations like this that simply aren't available to dynamically typed languages. Tracing JIT can only take you so far.
- deleted 9y ago[deleted]
- petters 9y agoThis is really true. I was a complete Java newbie and knew some Python when I joined Google. Yet I found working in an unfamiliar Java code base much, much easier here. Large Python code bases are really hard to understand and work in (here).
- yogthos 9y agoA lot of the same refactoring is possible in dynamic languages as in static ones. I recommend reading up on Term to see what's possible to do with JavaScript http://marijnhaverbeke.nl/blog/tern.html http://marijnhaverbeke.nl/blog/tern.html I use Cursive https://cursive-ide.com/ https://cursive-ide.com/ for working with Clojure, and it can do safe refactoring for symbols by doing static analysis of the source. It can show all usages of a symbol, rename it, do automatic imports, and so on. Another piece of tooling that's not available in any statically typed languages at the moment is REPL integration with the editor seen here http://vvvvalvalval.github.io/posts/what-makes-a-good-repl.html http://vvvvalvalval.github.io/posts/what-makes-a-good-repl.h... I find that the REPL driven workflow found in Lisps is simply unmatched. When you have tight integration between the editor and the application runtime, you can run any code you write within the context of the application immediately. This means that you never have to keep a lot of context in your head when you're working with the application. You always know what the code is doing because you can always run and inspect it. Having the runtime available during development gives you feedback much faster than the compile/run cycle. I write a function, and I can run it immediately within the context of my application. I can see exactly what it's doing and why. The main cost of static typing is that it restricts the ways you can express yourself. You're limited to the set of statements that can be verified by the type checker. This is necessarily a subset of all valid statements you could make in a dynamic language. Finally, dynamic languages use different approaches to provide specification that have different trade offs from static typing. For example, Clojure has Spec that's used to provide runtime contracts. Just like static typing, Spec provides a specification for what the function should be doing, and it can be used to help guide the solution as seen here https://www.anthony-galea.com/blog/post/hello-parking-garage-meet-clojure.spec/ https://www.anthony-galea.com/blog/post/hello-parking-garage... Spec also allows trivially specifying properties that are either difficult or impossible to encode using most type systems. Consider the sort function as an example. The constraints I care about are the following: I want to know that the elements are in their sorted order, and that the same elements that were passed in as arguments are returned as the result. Typing it to demonstrate semantic correctness is impossible using most type systems. However, I can trivially do a runtime verification for it using Spec: (s/def ::sortable (s/coll-of number?)) (s/def ::sorted #(or (empty? %) (apply <= %))) (s/fdef mysort :args (s/cat :s ::sortable) :ret ::sorted :fn (fn [{:keys [args ret]}] (and (= (count ret) (-> args :s count)) (empty? (difference (-> args :s set) (set ret)))))) The above code ensures that the function is doing exactly what was intended and provides me with a useful specification. Just like types I can use Spec to derive the solution, but unlike types I don't have to fight with it when I'm still not sure what the shape of the solution is going to be.
- kuon 9y agoI have been doing some elm, and refactoring is a MAJOR bonus. You can refactor your entire project, and when it compiles it usually works. It's funny how dynamic languages are seen as beginner friendly, while in reality they are not (ruby, js, python...).
- stephengillie 9y agoOne of my favorite parts of Powershell is optional typing. Variables are a generic "Object" type by default, which can hold anything from a string to array to "Amazon.AWS.Model.EC2.Tag" or other custom types. Or, type can be specified when setting the variable: [String]$myString = "Hello World!" This would generate a type error: [Int]$myString = "Hello World!" Often, typed and untyped variables will sit together: [Int]$EmployeeID,[String]$FullName,$Address = $Input -split ","
- GenericsMotors 9y agoIndeed! I think one of my favourites has to be: [xml]$someXmlDocument = Get-Content "path\to\file.xml" And you get a deserialized version of the XML text. Also the fact that you can use types when declaring function arguments, removing the need to manually test if an object of the desired type was passed. Powershell definitely strikes a good balance on type safety for a scripting language.
- amelius 9y agoSo when you call a function which takes a String as argument, do you need to cast the value manually? If no, then what is the use of the typesystem? If yes, isn't that cumbersome, since I suppose most library functions have typed arguments?
- CoolGuySteve 9y agoWhen I went from working at Apple to a language implementation group at another company, my views on Objective-C's duck typing + warnings for classes being useful and good was pretty heretical. It's nice to see other people agree with me. Especially when it comes to GUI programming, I really don't care if a BlueButton.Click() got called instead of RedButton.Click().
- wootness 9y agoThe biggest benefit of static typing is not a reduction of bugs...It's the speed and confidence with which one can accomplish a given task. IDE support, code completion, etc are so much better in a static environment. Take a random file from a pure JS codebase and compare it to something in Typescript. The first would require digging around to even begin to understand what the file is doing. Whereas TS, the code documents itself. The counterarguemnt - "it's slow to write" - hasn't been true for years with modern type inference and other features.
- k__ 9y agoI had the same experience, but I also have to say that the static type systems of some FP-languages feel really light-weight. So year, static typing doesn't buy you much, but in some languages it's at least cheap.
- hwayne 9y ago> So year, static typing doesn't buy you much, but in some languages it's at least cheap. I think this is key. The benefit of static typing isn't that they provide safety, it's that they provide _low-cost_ safety. For a large class of problems, types are cheaper than tests are. For other classes, tests are cheaper than types. The main downside of nonstatic languages is that you have to use tests for everything, even that class where types are a better choice.
- agentultra 9y agoI think what's often missing from these arguments is that statically checking (or inferring) homogenous lists is probably one of the most superficial uses of the type system in Haskell (and indeed not the interesting feature most power-users of Haskell are interested in as far as I can tell). What is interesting is using the type system to specify invariants about data structures and functions at the type level before they are implemented. This has two effects: The developer is encouraged to think of the invariants before trying to prove that their implementation satisfies them. This approach to software development asks the programmer to consider side-effects, error cases, and data transformations before committing to writing an implementation. Writing the implementation proves the invariant if the program type checks. (Of course Haskell's type system in its lowest-common denominator form is simply typed but with extensions it can be made to be dependently typed). The second interesting property is that, given a sufficiently expressive type system (which means Haskell with a plethora of extensions... or just Idris/Lean/Agda), it is possible to encode invariants about complex data structures at the type level. I'm not talking about enforcing homogenous lists of record types. I'm talking about ensuring that Red-Black Trees are properly balanced. This gets much more interesting when embedding DSLs into such a programming language that compile down to more "unsafe" languages.
- danharaj 9y agoList typing isn't as superficial as it seems. The following has happened to me multiple times, perhaps in the last month: I have a large code base. I want to replace a fundamental data structure to support more operations/invariants/performance guarantees. I change the type at the roots of the code base. My instance of ghcid notifies me of the first type error. I fix it. This repeats until the program compiles again. I run the tests. All the tests pass. This is insane in Python/C/Ruby. I've had to do it in C and Python. In Haskell I do it with impunity. The type system doesn't just check what my program does, it is the compass, map, and hiking gear that gets me through the wilderness.
- DubiousPusher 9y agoYup, love that about statically typed languages. This happens all the time for me in C#. I have several libraries I like that do a lot of code generation. When the project is young, directly handling the generated classes works well but as the project grows, I inevitably want to wrap the handling of the generated classes. It's awesome to be like, welp... it's time to handle this one type differently. Change the return type of an interface or the type of a container and just have the compiler tell you everything you broke.
- tree_of_item 9y agoYeah, actually I'm gonna go ahead and roll my eyes at the idea that parametric polymorphism is on the wrong side of the "diminishing returns of static typing". Less than ONE percent of Go code would benefit from type-safe containers?
- simon_o 9y agoThe biggest issue with claims like "there are only diminishing results when using a type system better than the one provided in my blub language" is that it assumes people keep writing the same style of code, regardless of the assurances a better type system gives you. "I don't see the benefit of typed languages if I keep writing code as if it was PHP/JavaScript/Go" ... OF COURSE YOU DON'T! This is missing most of the benefits, because the main benefits of a better type system isn't realized by writing the same code, the benefits are realized by writing code that leverages the new possibilities. Another benefit of static typing is that it applies to other peoples' code and libraries, not only your own. Being able to look at the signatures and bring certain about what some function _can't_ do is a benefit that untyped languages lack. I think the failure of "optional" typing in Clojure is a very educational example in this regard. The failure of newer languages to retrofit nullabillity information onto Java is another one.
- Merovius 9y agoThe article makes two main points: a) static typing has a cost and b) thus, any benefit it brings should be examined against that cost. I am sorry, but I don't really see how you stating more benefits of static typing really counters either of them. I recommend reading the article again. But this time, try not to read it as defending a specific language (I only mentioned my blub language so that it's a more specific and extensive reference in the cases where I use it - if you are not using my blub language, you should really just ignore everything I write about it specifically) and more as trying to talk on a meta-level about how we discuss these things. Because your comment is an excellent example of how not to do it and the kind of argument that prompted me to this writeup in the first place.
- Retra 9y agoThose are not really 'points', though; they are far too trivial. Obviously, nothing counters them, because they are tautologies that could just as well apply to any subject. The point is to explore a comparative difference in value, and that is realized through mastery of the tool, not merely living in a world where it exists.
- ruskimalooski 9y agoThese graphs really mean nothing. There is no data behind them. I might as well make a graph that conveys a non-descript correlation between how much an article bashes static typing & assertion and how high it is on HN.
- gipp 9y agoThey're just sketches. That's part of the point, and the article says that directly. The point isn't the exact shape or slope of the curves, but just their asymptotic behavior and the relationship of "correct features/day" to the other two. I.e. As long as the two curves have that general shape, then the "sweet spot" exists somewhere between 0-100%, the exact location of which depends on language, developer experience, and business priorities. The exact numbers are irrelevant to the article's point.
- ruskimalooski 9y agoBut even the asymptotes are an assumption derived from pure thought experiment.
- dwaltrip 9y agoMore realistically, it's an educated guess based off the author's personal experience as well as their understanding of the experiences of other developers operating under different constraints. The author makes it clear that the analysis is not perfectly rigorous. There is a very wide landscape between perfectly rigorous and completely useless. Do you think the article fails to hint at any of the fundamental dynamics of how type systems affect software development? How so?
- raquo 9y agoI'm not who you're replying to, but for me the charts didn't make sense either. For one example, I don't think it's a given that the green line (velocity vs % type-checked) should have a negative slope. Maybe in some cases, for some projects or some people, but certainly not universally. At least part of it would have been positive on almost all projects that I've worked on, and I'm not doing rocket science. Then, the combined chart just looks at the amount of bug-free output, completely ignoring the amount of bug-ridden output. That latter part doesn't just get discarded, it needs fixing, and bugs that were only discovered in production are expensive to discover, debug and fix. This is in addition to pretty much every other top level comment in this thread, a lot of which bring up important points that are unaccounted for even conceptually in the charts.
- mattnewton 9y agoI just don’t buy that go is some sort of sweet spot because it doesn’t have generics. Generics pretty much exist for maps and slices, because they are needed in real programs. The language designers just don’t let you make your own generic collections.
- namelost 9y agoYeah far from finding a sweet spot, Go exists in some kind of type system ghetto, because its type system is so crippled users have to resort to code generation (go generate). Neither Python nor Java programmers have to do that.
- lopatin 9y agoYeah Go is weird in that its static type system doesn't to provide you with great static typing power but instead it's just there as a sort-of sanity checker. If there's logic, they say write it with data structures and functions. Have invariants? Enforce them yourself. If Go is annoying with how little power it provides, that's fair, but other type systems can be just as annoying then, because when given the ability to, type astronauts will blast off into space, purely as a matter of honor or instinct. Besides, code generation isn't all that bad. Java programmers will eventually find some kind of code generation in their build setup (serialization/schema tools).
- bjz_ 9y agoYeah, I've noticed that Go APIs are very stringly typed. The APIs are not very self documenting, and it is hard to figure out whether something is nullable or not. Libraries often require you to initialised data in a partially invalid state and the whole thing feels quite error-prone and flaky.
- catnaroek 9y ago> Besides, code generation isn't all that bad. It is the number one thing that makes C++ templates unusable: semantics defined by means of code generation.
- 9y ago
- barrkel 9y agoThere's a point beyond which you spend more time proving things about your code than writing it, all the way up to the point where your ability to prove things about your code in your chosen type system starts to affect the kinds of solutions you can construct, and a different kind of complexity creeps in; representational complexity rather than implementation complexity. This can be a source of error, not just inefficiency.
- danharaj 9y agoJust a technical point that hints at a significant philosophical idea: The asymptote cannot reach 100% of program behavior in any finitary way. That would solve the halting problem. The x-axis should go off to infinity. Also, it's not a smooth progression. There are huge jumps in expressivity involved here. Going from Java-style types to Hindley-Milner to full System F are all massive jumps in expressivity. There are also incompatible features of type theories. Type theories are a fractal of utility and complexity. A type system doesn't only describe the behavior of the program you write. It also informs you of how to write a program that does what you want. That's why functional programming pairs so well with static typing, and in my opinion why typed functional languages are gaining more traction than lisp. How many ways are there to do something in lisp? Pose a feature request to 10 lispers and they'll come back with 11 macros. God knows how those macros compose together. On the other hand, once you have a good abstraction in ML or Haskell it's probably adhering to some simple, composable idea which can be reused again and again. In lisp, it's not so easy. A static type system that's typing an inexpressive programming construct is kind of a pain because it just gets in the way of whatever simple thing you're trying to do. A powerful programming construct without a type system is difficult to compose because the user will have to understand its dynamics with no help from the compiler and no logical framework in which to reason about the construct. So, a static type system should be molded to fit the power of what it's typing. The fact that every Go programmer I talk to has something to say about their company's boilerplate factory for getting around the lack of generics tells me something. This is only a matter of taste to a point. In mathematics there are a vast possibility of abstract concepts that could be studied, but very few are. It's because there's some difficult to grasp idea of what is good, natural mathematics. The same is in programming: there are a panoply of programming constructs that could be devised, but only some of them are worth investigating. Furthermore, for every programming construct you can think of there's only going to be a relatively small set of natural type systems for it in the whole space of possible type systems. Generics are a natural type system for interfaces. The idea that interfaces can be abstracted over certain constituents is powerful even if your compiler doesn't support it. If it doesn't, it just means that you have to write your own automated tools for working with generics. It's not pretty.
- tom_mellior 9y ago
- btown 9y agoAlso depends on your problem domain. If you have good test coverage but you're parsing strings found in the wild, you're going to spend a lot more time "debugging" your assumptions than AttributeErrors which would be caught by typing. Bug free code is not always the same as working code. Disclaimer: Python user scarred by email header RFC violations
- _Codemonkeyism 9y agoI like for example Refined https://github.com/fthomas/refined https://github.com/fthomas/refined not only for the static checking, scala> val i: Int Refined Positive = -5 <console>:22: error: Predicate failed: (-5 > 0). val i: Int Refined Positive = -5 but the expressive descriptions of a domain model.
- brango 9y agoWhy my favorite color is red not blue...
- zzzcpan 9y ago"I don't think it's particularly controversial, that static typing in general has advantages" That's not really true, just a belief. I give you an example to start understanding these things: the exact same program written in a very high level and very expressive language, like Perl, instead of Go, is going to have at least 3 times less code and since defect rates per line of code are comparable, you would end up with at least 3 times less bugs. Suddenly reliability argument of static typing doesn't make any sense. That's because in PL research there is a huge gap in understanding of how programmers actually think.
- raphinou 9y agoI think you are right, but you only cover producing code. For maintaining code, it is another story. If you have to take over an unknown code base, I think static typing will prevent bugs to be deployed, because the typing system will detect errors you might not be aware of due to your incomplete knowledge of the code. I was in favour of dynamic typed, but lean more and more towards static typing, like ocaml.
- Symmetry 9y agoThat's an argument for higher level languages over lower level ones rather than against dynamic typing. And I'm not sure you should expect the number of bugs per line to remain constant across languages. Extra lines required because you have to do your indexing by hand as you're iterating over a list certain increases the chances of an error but the extra '}' required to end the block in some languages increases line count with very little chance of causing an error.
- scarmig 9y agoAlthough I'm skeptical about the 1 to 3 ratio, let's run with it. Given a million line codebase written in Perl vs a three million line codebase written in Go, which do you think most engineers would prefer?
- 3pt14159 9y agoHonestly the Ruby or Python one, but I've never seen them because you don't need a million lines in Ruby or Python to get something productive built.
- thesz 9y agoThe effort to fix a defect is proportional to the time between introduction of a defect and it's discovery. This is a basic intuition behind all good practices, including CI, QA, etc. Types allow one to discover program defects (even generalized ones, when using some of the programming languages) in (almost) shortest possible amount of time. Types also allows one to constrain effects of various kind (again, use good language for this), which constraintment can make code simpler, safer and, in the end, more performant.
- millstone 9y agoAlso, retaining dynamic types at runtime enables you to find type errors that the static type system could not discover, or that were worked around. Language implementations that discard dynamic types make it harder to find defects.
- thesz 9y agoAlgebraic data types allow you to get any amount of dynamism you would needed. Have you familiarized yourself with Haskell?
- evmar 9y agoIn this thread: people will bring out the same tired arguments for or against static typing, without commenting on the actual content of the post, which was quite good! I have come to see type systems, like many pieces of computer science, can either be viewed as a math/research problem (in which generally more types = better) or as an engineering challenge, in which you're more concerned with understanding and balancing tradeoffs (bugs / velocity / ease of use / etc., as described in the post). These two mindsets are at odds and generally talk past each other because they don't fundamentally agree on which values are more important (like the great startups vs NASA example at the end).
- mattnewton 9y agoI think this post was extremely hand wavy. It stated the same divide that is already known, but doesn’t actually make any arguments to why Go or whatever lies on some part of the curve, because it assumes that the way you program at different points on the curve are roughly the same but with more type boilerplate. Higher kinded types offer entirely new ways to program, and stuff like optional typing in Python makes it all much more complex than just “how long do I spend writing and reading type declarations”. I was left with an impression that the author was content with go, and that’s pretty much it.
- yorwba 9y agoI agree. The graph of static checking vs. lines of code should really be factored into static checking vs. amount of annotations to achieve that level, amount of annotations to write vs. how much that slows you down, and amount of annotations that are already written (in your own code or libraries you use) vs. how much that speeds you up. And those will vary wildly depending both on the language and the programmer.
- mpartel 9y agoHaving programmed in languages ranging from Ruby to Coq, for web apps and games, I feel the sweet spot is somewhere in the neighborhood of Java/C#, i.e. include generics but maybe leave out stuff like higher kinds and super-advanced type inference (and null!). The main use case of generics, making collections and datastructures convenient and readable, is more than enough to justify the feature in my view, since virtually all code deals with various kinds of "collections" almost all of the time. It's a very good place to spend a language's "complexity budget". I wrote an appreciable amount of Go recently, with advice and reviews from several experienced Go users, and the experience pretty much cemented this view for me. An awful lot of energy was wasted memorizing various tricks and conventions to make do with loops, slices and maps where in other languages you'd just call a generic method. Simple concurrency patterns like a worker pool or a parallel map required many lines of error-prone channel boilerplate.
- runT1ME 9y ago> An awful lot of energy was wasted memorizing various tricks and conventions to make do with loops, slices and maps where in other languages you'd just call a generic method. I feel the same way going from languages with HKTs back to Java/C#... Not sure why you think they're not as useful, it sounds like you're making the same argument as OP but just moving the bar one notch over...
- mpartel 9y agoI am. I think the OP is fundamentally right about the sweet spot being pretty far from either extreme, I just disagree slightly about where exactly :) Subjectively, I use ordinary generics all the time, but see the need for HKTs only occasionally. It's entirely possible I'm not experienced enough to see most of their possible use cases, but then I'd wager most programmers aren't.
- willtim 9y agoIn retrospect, HKTs are arguably Haskells greatest innovation, enabling extremely general abstractions and huge amounts of code reuse.
- js8 9y agoLike other commenters, I disagree there are diminishing returns to static typing itself, but rather diminishing returns to proper engineering in certain cases (i.e. do something as perfectly as possible). By adding types (and in the extreme, dependent types), you're allowing compiler to prove more things about the code (to check correctness or generate more optimal code). If you actually need to prove more things, then it's better to leave that for a compiler rather than human. Of course, if you're writing e.g. web scraping script, you don't need these guarantees and then you don't have to care about types. But the better engineering you want, the more static typing will help and there is no diminishing returns.
- guicho271828 9y agoCorrect and useless programs are useless. Quite simple.
- seasoup 9y agoI really enjoyed how the analysis shows that different developers can have different equally valid opinions on this topic. It's where you place your values and preferences of programming, modified by what you are programming. The failure state of a cat photo sharing web app likely isn't as dramatic or important as that of a financial system or driverless car code. Great article.
- continuational 9y agoStatic typing reduces the time you spend on debugging. Automatically reducing errors in code is not just for reducing errors in the resulting program. It also greatly reduces the time you spend on hunting bugs, especially if you have a poorly designed type systems where errors are reported far from their origin. Null, interface{}, NaN etc. propagates errors and thus gives you a stacktrace that is worthless when it finally fails. It's a waste of time.
- hellofunk 9y agoIn my experience, the time saved from writing in a statically typed language where the compiler catches the bugs for you is made up by having to work more closely with the compiler, typically write more code (type annotations and other things) and in general spend that same time on compile-time rather than run-time bug hunting. Dynamically typed languages typically involve a lot less code, which is time gained. That both forms of languages are popular shows that there are benefits in overall productivity to each; they are just different benefits.
- whyever 9y agoThe thing is that errors at compile time get reported almost instantly, but errors at runtime might be reported hours after you started your program if you are unlucky.
- hellofunk 9y agoThat's entirely correct, and one of the tradeoffs. However, in a statically-typed language, you must satisfy the type checker for everything, which adds development time. In reality, there might be a small percentage of functions in your code base for which errors (either compile-time or run-time) would likely crop up, yet you must pay that cost for 100% of them. So that's really where the debate comes from. Dynamically typed languages can get around this problem by generative testing (in Clojure's case) which allow very fine-tuned aspects of your system's requirements to be automatically tested before run-time without writing tests, which offers some of the same confidence as a compiler.
- nwellinghoff 9y agoTime and time again I can make a well written functioning program in Java or C# at least twice as fast than using js and brothers. Sure it might have more "lines". Who freaking cares. My team and I square off all the time. "K, you use node I will use java" And the Java dev always wins. Its just so much faster, cleaner and mature. Its NO CONTEST.
- fny 9y agoThere's one huge benefit to static typing people often forget: self documentation. While, yes, top-quality dynamic code will have documentation and test cases to make up for this deficiency, it's often still not good enough for me to get my answer without spelunking the source or StackOverflow. I feel like I learned this the hard way over the years after having to deal with my own code. Without types, I spend nearly twice as long to familiarize myself with whatever atrocity I committed.
- hellofunk 9y agoMany dynamically typed languages offer excellent runtime contract systems (Racket, Clojure) that serve as an implicit documentation at least as well as a statically-type language. Often more so, because you can express a lot of things in contracts that are not easily expressed in type systems.
- suprfnk 9y ago> because you can express a lot of things in contracts that are not easily expressed in type systems. Can you give an or some example(s) of this?
- sigstoat 9y agoyou can put arbitrary functions in a contract. with static typing that requires dependent types. and while i'm a fan, that's an enormous can of complexity to bust open. say you've got a function that takes a list of numbers, and some bounds, and gives you back a number from the list that is within the bounds (and maybe meets other criteria, whatever). your contract for the function could require not only that the list be comprised of numbers, and the bounds are numeric, but also that the lower bound is <= the upper bound, and that the return value was actually present in the input list.
- z3t4 9y agoI consider Reading the source code to see what something does is a feature, if you can understand the code that is. If the code is easy to understand, there will be less bugs.
- snambi 9y agoAny program that is non-trivial meaning 100K+ lines of code, involves many developers over 2+ years of time, should be written in a statically typed language.
- 201709User 9y agoThat requires some sort of prophecy abilities. Why not play it (type-) safe?
- hellofunk 9y agoThat really means nothing. 100K+ lines of code is an arbitrary number. For that many lines of C++, a similar Clojure solution to the same problem would be a small fraction of that. And many widely-used Clojure libraries are in production all over the industry for many years.
- valuearb 9y agoThe two languages I develop in are Javascript and Swift. Couldn't be more different in type safety. I love everything about Swift except the compile times and occasionally inscrutable compile error messages. I love the interactivity of Javascript, but despise the lack of types, it's like I'm sketching out the idea for a program instead of directly defining what it is. And the lack of types burns me occasionally.
- shalabhc 9y agoQuestion for all static or dynamic typing proponents: do you see your language/type-system as a great and scalable way to program large distributed systems in 10 years? 20 years?
- willtim 9y agoOur industry has not yet even scratched the surface of what types can offer: Types for enforcing architectures and controlling effects, types for checking correct use/free of scarce resources, types for verifying protocol implementations etc etc. Currently, half the industry is using schema-less json and dynamic languages; so really it is far too early to generally talk about any diminishing returns.
- 14113 9y agoWell said. This article is essentially dismissing a technique that is barely used, with the argument that the technique is not the entire solution. Of course it isn't, but that doesn't change the benefits that it can bring.
- agumonkey 9y agoThe industry has other issues, the constant cruft, tech debt and turnover. Lots of people make money through this, they won't accept making better software if it make them appear smaller and too cheap.
- hwayne 9y agoThere's a lot of great things our industry doesn't use: contracts, proper fuzz testing, cleanroom, formal specification, constraint solvers, _checklists_. We might (not necessarily, but _might_) be in a place where types are diminishing returns with respect to other low-hanging fruit.
- willtim 9y agoYes it's true that retrofitting better type systems into existing languages may not be low-hanging fruit. But developers have shown a willingness to adopt new languages when they see clear benefits.
- hwayne 9y ago> Yes it's true that retrofitting better type systems into existing languages may not be low-hanging fruit. Disagree here, actually! Javascript (Typescript) and Python (mypy) are both seeing pretty big benefits from adding gradual typing.
- catpolice 9y agoStatic typing prevents bugs in code to the degree that the programmer can correctly encode the desired behavior of the program into the type system. Relatively little behavior can be encoded in inexpressive type systems, so there's a lot of room for bugs that have nothing to do with types. A lot more behavior (e.g. the sorts of invariants mentioned in agentultra's top level comment) can be encoded in a more expressive type system, but you then have the challenge of encoding it /correctly/. A lot of that kind of thinking is the same as the kind of thinking you'd have to do writing in a dynamic language, but you get more assurances when your type system gives you feedback about whether you're thinking about the problem right. For my money, I work in a primarily dynamic language and I already have a set of practices that usually prevent relatively simple type mismatches so I very rarely see bugs slip into production that involve type mismatches that would be caught by a Go-level type system, and just that level of type information would add a lot of overhead to my code. But if I were already using types, a more expressive system could probably catch a lot of invariance issues. So I feel like the sweet spot graph is more bimodal for me: the initial cost of switching to a basic static type system wouldn't buy me a lot in terms of effort-to-caught-bugs-ratio, but there's a kind of longer term payout that might make it worth it as the type system becomes more expressive.
- pdonis 9y ago> Static typing prevents bugs in code to the degree that the programmer can correctly encode the desired behavior of the program into the type system. Exactly. The author of the article implicitly equates "statically verified code" with "bug-free code". But that's not correct. It's quite possible (and even, dare I say it, fairly common) to have code that expresses, in perfectly type-correct fashion, an algorithm that doesn't do what the user actually wants it to do. Static typing doesn't catch that.
- avg_programmer 9y agoThe article was not trying to discuss how to make programmers smarter. No language is going to help with that so there is no point in talking about it. As far as the scope of the article is concerned, it's fair to say that statically verified code equals bug-free code.
- hwayne 9y agoSometimes I wonder if we're arguing the wrong thing, where we think we're arguing static vs dynamic typing but what we're _actually_ arguing is static vs no-static typing. Haskell is static and not dynamic. Ruby is dynamic but not static. Python, starting with 3.5, is sorta both. C# is definitely both. All static typing means is that type information exists at compile time. All dynamic typing means is that type information exists at runtime. You generally need _at least_ one of the two, and the benefits each gives you is partially hobbled by the drawbacks of the other, so most dynamic languages choose not to have static typing. I also feel that dynamic languages don't really lean into dynamic typing benefits, though, which is why this becomes more "static versus no static". One example of leaning in: J allows for some absolutely crazy array transformations. I don't really see how it could be easily statically-typed without losing almost all of its benefits.
- brightball 9y agoHonestly, I think you've nailed it. The key is balance. Pure static does create a lot of extra up front cruft at the expense of long term safety. Pure dynamic does create a much faster path to features at the expense a lot of long term confusion. The reason we have this conversation is because of web applications where everything is travelling over the wire as a string, consumed by the web server as a string, converted by whatever language the server is in...into something that it can use...9/10 times validated to make sure it reflects what we need and then stuff into a database. In the case that you're using a SQL database, a huge number of people are enforcing types at the database layer and the validation layer. Since so much is "consume and store" followed by "read and return" the types at that server layer end up creating a ton of extra work that in many cases shows little to no benefit. At the point that you're doing more in server layer, suddenly it becomes a lot more useful. At the point you're working on desktop, mobile, embedded, console, computational and graphics...static is going to provided more value. At the point you're working on web in front of a database, the value is much more questionable. This is really one of the reasons I'm such a huge Elixir fan because IMO it strikes that perfect balance where I live...on the server in front of a database. You get static basic types with automatic checking via dialyzer and you can make it stricter as necessary.
- solatic 9y agoOP draws a false one-dimensional relationship between types vs tests in terms of code quality. Writing expressive types instead of tests does much more than affect a quality curve - it changes the way you approach the problem you are trying to solve. The classic Haskell example is understanding how IO being a monad allows you to push impurity to the edge of your system. Start-ups decide not to write MVPs in languages like Haskell or Idris not because those languages aren't "rapid" enough, but because it's too difficult to find programmers experienced in those languages on the labor market. It's already difficult enough to find competent programmers - no founder wants to make their hiring woes even more difficult.
- sordina 9y agoSorry to contradict you, but we wrote an mvp in rails even though we have 3.5 experienced Haskell programmers on staff. We did this because we knew we could build some web stack apps with all the trimmings much faster in ror. So there is at least one counter example.
- yawaramin 9y agoI don't think it's really a contradiction. In a startup you still have to choose the quickest path that you think will lead to success. It just depends on what your definition of success is. RoR can be a safe choice even for Haskell devs if they just want to build an off-the-shelf webapp with all the trimmings. But if your definition of success is that you want to create a formally-verified smart contract platform and cryptocurrency, you're going to use something like Haskell or OCaml: https://github.com/tezos/tezos https://github.com/tezos/tezos
- mannykannot 9y agoFirstly, thank you for wanting to take an open-minded look into the issue, rather than simply defend a position that you have already committed to. You write "Why then is it, that we don't all code in Idris, Agda or a similarly strict language?... The answer, of course, is that static typing has a cost and that there is no free lunch." I take it that you wrote "of course" here through assuming that there must be some objective reason for the choice, and that it depends solely on strictness, but languages don't differ only in their strictness, so choices may be made objectively on the basis of their other differences, and we also know that choices are sometimes made on subjective or extrinsic grounds, such as familiarity. I don't know what proportion of professional programmers are familiar enough with Iris or Agda to be able to judge the value proposition of their strictness, but I would guess that it is rather small. Now, to look at the sentences I elided in the above quote: "Sure, the graph above is suggestively drawn to taper off, but it's still monotonically increasing. You'd think that this implies more is better." As the graph is speculative, it cannot really be presented as evidence for the proposition you are making. I could just as well speculate that static program checking does not do much for program reliability until you are checking almost every aspect of program behavior, and that simple syntactical type checking is of limited value. That would be consistent with the fact that there is little empirical evidence for the benefit of this sort of checking, and explain why most people aren't motivated to take a close look at Iris or Agda. In this equally-speculative view of things, current language choices don't necessarily represent a global optimization, but might be due to a valley of much more work for little benefit between the status quo and the world of extensive-but-expensive static checking.
- noncoml 9y agoI think there are two kind of static typing languages. The ones that static typing is for helping the compiler(eg C) and the ones that it’s for helping the user(eg Typescript). I think Go with its lack of algebraic type is more of the first, helping the compiler, so I wouldn’t use it as a good example of static typing. Haskell, OCaml and Rust would make excellent case studies, but we have nothing to compare against. So IMHO the best way to compare static typing vs dynamic typing is by comparing Typescript against JS. And in my experience the difference when writing code is huge. It completely eliminates the code-try-fix cycle during development.
- FranOntanaya 9y agoIt bothers me that types as representation of hardware constraints are mixed up with types as a machine readable subset of validation. It makes the higher level types seem more transcendental than they are, and also seems to put actual validation on a second rate level. End of the day if an argument is the right scalar or interface you'll get the same result on runtime whether you hinted it -- for one's quality of life improvements -- or checked it with some boilerplate validation. Worst case scenario people will forgo encoding known stricter constraints after generally hinting the expected type.
- flavio81 9y agoWhat amuses me in all "static typing versus..." discussions, is that it usually it is the comparison between two camps: Camp A: Languages with mediocre static typing facilities, for example: -- C (weakly typed) -- C++ (weakly typed in parts, plus over-complicated type features) -- TypeScript (the runtime is weakly typed, because it's Javascript all the way down) Camp B: Languages with mediocre dynamic typing facilities, for example: -- Javascript (weakly typed) -- PHP 4/5 (weakly typed) -- Python and Ruby (no powerful macro system to help you keep complexity well under control or take fulll advantage of dynamicism) Both camps are not the best examples of static or dynamic typing. A good comparison would be between: Camp C: Languages with very good static typing facilities, for example: -- Haskell -- ML -- F# Camp D: Languages with very good dynamic typing facilities, for example: -- Common Lisp -- Clojure -- Scheme/Racket -- Julia -- Smalltalk I think that as long as you stay in camp (A) or (B), you'll not be entirely satisfied, and you will get criticism from the other camp.
- fulafel 9y agoWhat makes you put Python and JS in the same basket here? Python is widely raised as a language that has a good dynamic typing system with strong types and good type error handling - arguably better than Lisps (nil punning). JS is infamous for the opposite. Macros are quite orthogonal to this.
- flavio81 9y ago>What makes you put Python and JS in the same basket here? I'm very well versed in Python (i've delivered two financial software systems done in Python, written entirely by yours truly). However its features and facilities pale in comparison to the languages i listed in camp "D".
- nnq 9y ago> Macros are quite orthogonal to this. You ain't gonna to find any sane way to combine macros with a powerful type system in a way the doesn't make a 140+ IQ a requirement for any programmer touching the code using these features in a real world project... Problem with programming language design is that the ideal/Nirvana solutions lie at the edge, or beyond, the limits of human intellect. If you want something that can be learnt and understood with reasonable effort (like in not making "5+ years experience" a requirement for even basic productivity on an advanced codebase), you're going to have to compromise heaviliy! The most obvious ways to compromise are throwing away unlimited abstraction freedom (aka "macros"), or type systems. Sorry to break it to ya, but we're merely humans, and not that smart...
- bad_user 9y agoThose line charts are totally made up, with arguments pulled out of thin air to support this line: > "Go reaps probably upwards of 90% of the benefits you can get from static typing" That 90% number is totally made up as well. I don't see evidence that the author actually worked with Haskell, or Idris, or Agda these being the three static languages mentioned. Article is basically hyperbole. If I am to pull numbers out of my ass, I would say that Go reaps only 10% of the benefits you get with static typing. This is an educated guess, because: 1. it gives you no way to turn a type name into a value (i.e. what you get with type classes or implicit parameters), therefore many abstractions are out of reach 2. no generics means you can't abstract over higher order functions without dropping all notions of type safety 3. goes without saying that it has no higher kinded types, meaning that expressing abstractions over M[_] containers is impossible even with code generation So there are many abstractions that Go cannot express because you lose all type safety, therefore developers simply don't express those abstractions, resorting to copy/pasting and writing the same freaking for-loop over and over again. This is a perfect example of the Blub paradox btw. The author cannot imagine the abstractions that are impossible in Go, therefore he reaches the conclusion that the instances in which Go code succumbs to interface{} usage are acceptable. > "It requires more upfront investment in thinking about the correct types." This is in general a myth. In dynamic languages you still think about the shape of the data all the time, except that you can't write it down, you don't have a compiler to check it for you, you don't have an IDE to help you, so you have to load it in your head and keep it there, which is a real PITA. Of course, in OOP languages with manifest typing (e.g. Java, C#) you don't get full type inference, which does make you think about type names. But those are lesser languages, just like Go and if you want to see what a static type system can do, then the minimum should be Haskell or OCaml. > "It increases compile times and thus the change-compile-test-repeat cycle." This is true, but irrelevant. With a good static language you don't need to test that often. With a good static type system you get certain guarantees, increasing your confidence in the process. With a dynamic language you really, really need to run your code often, because remember, the shape of the data and the APIs are all in your head, there's no compiler to help, so you need to validate that what you have in your head is valid, for each new line of code. In other words this is an unfair comparison. With a good static language you really don't need to run the code that often. > "It makes for a steeper learning curve." The actual learning is in fact the same, the curve might be steeper, but that's only because with dynamic languages people end up being superficial about the way they work, leading to more defects and effort. In the long run with a dynamic language you have to learn best practices, patterns, etc. things that you don't necessarily need with a static type system because you don't have the same potential for shooting yourself in the foot. > "And more often than we like to admit, the error messages a compiler will give us will decline in usefulness as the power of a type system increases." This is absolutely false, the more static guarantees a type system provides, the more compile time errors you get, and a compile time error will happen where the mistake is actually made, whereas a runtime error can happen far away, like a freaking butterfly effect, sometimes in production instead of crashing your build. So whenever you have the choice, always choose compile-time errors.
- cleandreams 9y agoMy 2 cents: dynamic typing works okay for library consumers. For libraries themselves though, or platform code, the disadvantages are real. It is harder to fix and extend code when you don't know who calls it, how they call it, what they get in return. Complex code becomes littered with 'black holes'. That is a big part of why facebook implemented Hack. I heard a talk by one of the developers. Even now there are PHP blackholes in the Facebook code base that they can't migrate to Hack.
- geokon 9y agoI think talking about a sweet spot is correct I've been thinking about the trajectory of C++ language development recently and the emphasis has definitely been on making generics more and powerful. You watch CppCon talks and see all this super expressive template spaghetti and see that while it's definitely a better way to write code - the syntax is just horrifying and hard to "get over" Just like when "auto" took off and people starting thinking about having "const by default" - I'm starting to think that generic by default is the way to go. The composability of generic code is incredible powerful and needs to be more accessible However the other end of the spectrum: dynamic code leaves a lot of performance on the table and leads to runtime errors
- avg_programmer 9y agoWhat are the costs of statically typed languages? The author stated "thinking about the correct types" and "increases compile times" among some other, weaker (imo) costs. What is wrong with "thinking about the correct types"? You are thinking about the same things in a dynamic language, right? For example, say you need to know about things that are "thennable". Weather you are in a statically typed language or not, you are still checking for the same thing: does it have the then() method? The tradeoff is in reading vs implementing code. With a statically typed language, you can easily search for implementers of the Thennable interface and you are guaranteed to be show every implementer. The downside is that you have to write a few more lines of code to satisfy the static typing. With a dynamically typed language, you have to find the implementers yourself, but you can just slap a then method on anything and it will work. I am biased toward static typing so I am interested to hear counter points.
- hellofunk 9y agoOne very simple and significant cost is developer time. It simply takes less time to write code in a dynamically-typed language. You don't have a compiler to please, you don't write extra code to massage types, annotate types, etc, and most dynamically typed languages are pretty elegant (i.e. Clojure), where you can pack a lot of punch in just a few characters. So the trade off is: static typing gives you more compile-time certainty, but at a cost of spending more time developing your code. Dynamic typing gets you to a working product or prototype typically much much faster, but with added run-time debugging. Each has its benefits and costs. In my experience, there is no doubt that dynamically typed languages are faster-to-production than statically-typed. This doesn't mean that I don't admire static typing, though, because most developers appreciate some degree of purity in their work.
- hellofunk 9y agoThere is one aspect to this debate that is worth pointing out. What about generative testing, which is possible in static or dynamically typed languages? The article mentions that testing is perhaps more important in a dynamically typed language since there is less compiler support. But for example, Clojure rolled out the very clever Clojure.spec library that allows you to precisely specify all details relating to function arguments, data structures, etc, in even more fine-tuned methodology than just types; you can specify that the second argument to a function must be larger than the first, or that a function should only return a value between 5 and 10, etc. These "specs" have the interesting property of being run-time checked or compile-time checked in the form of automatic tests, which can generate inputs based on the specs. In such a case, the line between these two type environments narrows.
- yawaramin 9y agoClojure.spec is very clever, but it can be exactly duplicated in a statically-typed language by unit or property testing. It doesn't bring anything to the table that is totally a superset of static typing. > In such a case, the line between these two type environments narrows. Not really. Static types still offer you total proofs of the properties you encode as types, not just experimental results of tests.
- hellofunk 9y agoGenerative testing is just one application of Clojure.spec. It does more than just aid in testing. It doubles as a runtime contract system, a data coercion system, and some folks are using it for compile-time checks as well (not in the testing sense, though I haven't read up on how they are doing that). It is not a proof-like system, but outside of dependent typing, static typing does not catch value-related bugs, but Clojure.spec can. In a static type system, how easily would it be to exactly specify and guarantee that a function's second parameter is of a higher value than its first, or that a function's output is an integer between 5 and 50, etc? Clojure.spec is just predicate functions composed together to define the flow of data in a program, and those compositions can be used in a variety of ways.
- amelius 9y agoCan't we have tools that automatically perform the static typing for us, perhaps in an interactive way? (I'm not talking about systems which just infer types automatically).
- vhiremath4 9y ago> “And more often than we like to admit, the error messages a compiler will give us will decline in usefulness as the power of a type system increases.” Can someone explain this?
- coding123 9y agoI'm converting a codebase of Javascript of about 200+ js files to Typescript today. I am about 5% complete... already found two places where the argument list was wrong and was being sent into a void. I also see the code that was making up for the fact that the third argument was being ignored (basically patching downstream because they thought the feature was broken). Now this codebase was written with a high degree of quality (it's pretty good but not perfect), but the lack of compile (and of course runtime)-time checks has caused waste. The second phase of my project to convert all promises to RX Observables :)
- kjaer 9y agoIf you're just rewriting these Promises because the syntax is too verbose, you might be interested in checking out async/await as another alternative; I just rewrote some Promises to that recently, and it's really, really nice. Of course, if you prefer RX Observables, go right ahead :)
- coding123 9y agoThanks for the note, I am looking into it right now. One area that may grind my head with async await however is that there is a lot of Promise.all work in this codebase. Would you still use async/await constructs when you need to do a lot of fork/join/merge stuff? (sorry for the derail HN)
- kjaer 9y agoIf you're using Promise.all to run code in parallel, then async await can't really replace that, as far as I know. But you can still use `await Promise.all(...)`, which will free you from having callbacks everywhere; running parallel code will no longer have to look so different from running it sequentially, which is quite nice.
- Longwelwind 9y agoYes, of course ! https://jsfiddle.net/0wc0vjw2/1/ https://jsfiddle.net/0wc0vjw2/1/
- woolvalley 9y agoI would like lots of static typing, even more than we have now, but an ability to turn it off for faster compile times during some parts of development.
- platz 9y agohttps://www.theatlantic.com/technology/archive/2017/09/saving-the-world-from-code/540393/ https://www.theatlantic.com/technology/archive/2017/09/savin... Software failures are failures of understanding, and of imagination. The problem is that programmers are having a hard time keeping up with their own creations. dynamic typing simply doesn't scale.
- iamleppert 9y agoIt's far more useful to implement validation and type checking via introspection and interrogation of type, quantity, structure, size, or some other property at runtime in a dynamic programming language than to pedantically have to type all your variables. Most interesting types are far from the basics of different size numbers, string and objects anyway. It's better to trade a fast and quick runtime type error than a lengthy compile-time type checking process, because less code needs to be evaluated at run-time to expose the type error. See the "Worse is better" principle in language design. Wouldn't it be great if we can use the computer to figure out what the types should be by a runtime evaluation of the code and save precious human time for things only humans can do? I don't have to think or decorate my speech with types of noun, verb, pronoun, adjective etc. when I speak, but I'm still able to communicate very effectively, because your brain is automatically adding the correct type information based on context that helps you understand what I'm saying, even with words that have multiple types. Granted, natural language is different than programming language but there was once a trend to try and make programming languages more like human language, not less so.
- yawaramin 9y ago> It's far more useful to implement validation and type checking via ... runtime in a dynamic programming language than to pedantically have to type all your variables. How is that? I'm not seeing the increased utility. > It's better to trade a fast and quick runtime type error.... What if the runtime type error crashes your app in production and loses your company money? What if it's something that slipped through your end-to-end integration testing because certain unlikely conditions never got covered, but they happened in production? > ... than a lengthy compile-time type checking process,... There are several modern compilers which are quite fast: D, OCaml, Java. > ... because less code needs to be evaluated at run-time to expose the type error. With static type checking, no code needs to be evaluated at runtime to expose a type error. Does dynamic typechecking offer a reduction over that? > Wouldn't it be great if we can use the computer to figure out what the types should be by a runtime evaluation of the code and save precious human time for things only humans can do? Wouldn't it be great if the computer would figure out the types at compile time and save us from having to manually input them? Well, the computer can do that, thanks to type inference. Several popular languages offer full, powerful type inference.
- tiuPapa 9y agoSo the article does praise Go, but how is Rust? Does it strike that sweetish spot? Is it a language a startup should use?
- djur 9y agoRust's type system is much closer to Haskell than Go, and even advocates of the language will admit that it can sometimes be very difficult to convince the compiler that your program is valid. Compile speed isn't great either, although it's been improving. I would say that Rust is pretty much on the other end of the scale from the author's supposed "sweet spot".
- solidsnack9000 9y agoI wonder if they would praise Java, especially ancient Java. It was a very similar language. Easy concurrency was a big selling point. Generics were a matter of casting to Object. What’s old is new again, though one can hardly imagine cat-v touting the merits of Java.
- alkonaut 9y agoThere are 3 main areas of interest in the discussion of benefits of static vs dynamic typing. - Quality (How many bugs) - Dev time (How fast to develop) - Maintainability (how easy to maintain and adapt for years, by others than the authors) The argument is often that there is no formal evidence for static typing one way or the other. Proponents of dynamic typing often argue that Quality is not demonstrably worse, while dev time is shorter. Few of these formal studies however look at software in the longer perspective (10-20 years). They look at simple defect rates and development hours. So too much focus is spent on the first two (which might not even be two separate items as the quality is certainly related to development speed and time to ship). But in my experience those two factors aren't even important compared to the third. For any code base that isn't a throwaway like a one-off script or similar, say 10 or 20 years maintenance, then the ability to maintain/change/refactor/adapt the code far outweigh the other factors. My own experience says it's much (much) easier to make quick and large scale refactorings in static code bases than dynamic ones. I doubt there will ever be any formal evidence of this, because you can't make good experiments with those time frames.
- jackmott 9y agoperformance at runtime is usually factor in type systems as well.
- quickben 9y ago4. Performance. There is software that can't be slow.
- eloff 9y agoIncredulous that people would downvote this.
- eloff 9y agoSeriously with the downvotes? Dynamic languages are obviously slower than static languages in general. Some special cases aside. Performance is a concern for some projects - you wouldn't write an OS, database kernel, or mainstream game engine in a dynamic language. How is that not a valid concern in the dynamic vs static typing argument? The parent comment has a legitimate point.
- zengid 9y agoCouldn't these discussions benefit from an inclusion of actual empirical evidence? Here's a list of some such studies: http://danluu.com/empirical-pl/ http://danluu.com/empirical-pl/
- tabtab 9y agoI've generally felt that each shines in different areas. Static typing is best for lower-level infrastructure and shared API's, while dynamic is better for gluing these all together toward the "top" of the stack, closer to the UI and biz logic. The problem is that languages tend to be all one or the other so that we have to make choice. What's needed is a language (or language interface convention) that can straddle both. A given class or library can be "locked down" type-wise to various degrees as needed.
- hyperpallium 9y ago1. performance dominates (like 80:20) 2. tooling 3. doc (becomes crucial on large projects) 4. correctness Formal correctness doesn't really matter. Anecdotally (since that's really all we have), I find in practice, very few bugs are caught by the type-checker. Further, code is usually not typed as accurately as the language allows. i.e. the degree of type-checking is a function of the code; the language only provides a maximum. In a sense, every value has a type, even if it's not formally specified or even considered by the programmer, in the same sense that every program has a formal specification, even if it's not formally specified. Upfront design is the price. Which is difficult to pay when the requirements are changing and/or not yet known.
- nv-vn 9y agoWhat language in specific are you applying this to? I.e. what is the type checker that is catching few bugs?
- lisper 9y ago100% statically-type-checked code != 100% bug-free code. That would require solving the halting problem. So you have to test everything anyway if you need high reliability.
- voidmain 9y agoThis argument is incorrect. The "halting problem" is the problem of determining if an arbitrary program halts. It is not impossible to prove, and verify mechanically, that a particular program halts. The state of the art is not up to proving every desirable property of every program that we would like to build. But that has nothing much to do with computability. And some extremely impressive things have been done, like the seL4 separation kernel, which has static proofs of, among other things, confidentiality, integrity, and timeliness, and a proof that its binary code is a correct translation of its source.
- lisper 9y ago> It is not impossible to prove, and verify mechanically, that a particular program halts. OK, let's put that to the test. Here is a particular program: let x = 6 let y = 3 while true: if y>x then halt if is_prime(y) and is_prime(x-y) then x = x + 2 y = 3 else y = y + 2 endif Can you tell me if it halts or not? > The state of the art is not up to proving every desirable property of every program that we would like to build. Isn't that exactly the same as what I said? > But that has nothing much to do with computability. What does it have to do with then? > some extremely impressive things have been done Yes, in some very particular cases. But note that even a proof of correctness is not a guarantee that the code is bug-free. http://spinroot.com/spin/Doc/rax.pdf http://spinroot.com/spin/Doc/rax.pdf
- voidmain 9y agoI think you have missed my point. I am not saying that humans are able to solve the halting problem! Nor am I saying that static verification is always better than testing. I am saying that you don't need a halting oracle to express and verify arbitrary properties in a static type system, because a static type system can and will reject programs that would not have type errors dynamically. If you write this program in a statically checked language: let x : int = 6 let y : int = 3 while true: if y>x then break if is_prime(y) and is_prime(x-y) then x = x + 2 y = 3 else y = y + 2 endif x = "foobar" I can tell you that it will not type check. And for the same reason, if you write the same program in a language that can express termination and claim that it terminates, the program will not type check until you have supplied a proof of (edit: the negation of!) Goldbach's conjecture in a form that the type system understands.
- magice 9y agohttps://dl.acm.org/citation.cfm?id=2635922 https://dl.acm.org/citation.cfm?id=2635922 Just ONE study, so don't take too much heed. That said, apparently: * Strongly type, statically compiled, functional, and managed memory is least buggy * perl is REVERSELY correlated with bugs. Interestingly, Python is positively correlated with bug. There goes the theory about how Python code looks like running pseudo-code... Snake (python's, to be more precise) oil? * Interestingly, unmanaged memory languages (C/C++) has high association with bugs across the board, rather than just memory bugs. * Erlang and Go are more prone to concurrency bugs than Javascript ¯\_(ツ)_/¯. Lesson: if you ain't gonna do something well, just ban it. All in all, interesting paper.
- katastic 9y agoThis site has a strange fascination with hatred of static languages. I really don't get it. My only guess is that modern colleges teach dynamic languages to students and so they're more familiar with it. Perhaps their teachers even stress that static languages are inferior. To me, it's right tool for the right job. I have no problem spinning up a static language for performance and outsourcing the scripting to a dynamic language like Python for the best of both worlds in terms of speed, and rapid development.
- ratherbefuddled 9y agoI guess the only bit I don't really agree with is this: > upfront investment in thinking about the correct types being a cost. Surely you have to do this whether the compiler will check your work or not, and if you just don't do the thinking you'll end up with bugs? Isn't this a benefit?
- oldandtired 9y agoIt has been interesting to see the to and froing of arguments for and against static typing in the discussions here. Though I am not a type theorist (I only dabble in compilers and language design), I have noted that many people conflate static typing and dynamic typing with other additional ideas. Static typing has certain benefits but also has certain disadvantages, dynamic typing has certain benefits but also has certain disadvantages. What I find interesting is that few people fall into the soft typing arena, using static typing where applicable and advantageous and using dynamic typing where applicable and advantageous. Static typing has a tendency in many languages to explode the amount of code required to get anything done, dynamic typing has a tendency to produce somewhat brittle code that will only be discovered at runtime. The implementation of static typing in many languages requires extensive type annotation which can be problematic. But what is forgotten by most is that static typing is a dynamic runtime typing situation for the compiler even when the compiler is written in a static typed language. Instead of falling into either camp, we need to develop languages that give us the beast of both world. Many of the features people here have raised as being a part of the static typing framework have been rightly pointed out as being of part of the language editors being used and are not specifically part of the static typing regime. Many years ago a similar discussion was held on Lambda-the-Ultimate, and the sensible heads came to the conclusion that soft typing was the best goal to head for. Yet, in the intervening years,when watching language design aficionados at work, they head towards full static typing or full dynamic typing and rarely head in the direction of soft typing (taking advantage of both worlds). S, the upshot, this discussion will continue to repeat itself for the foreseeable future and there will continue to NOT be a meeting of minds over the subject.
- zzbzq 9y agoMaybe part of the problem is I can't picture what you're actually talking about with soft typing. I can tell you C#/.NET has the DLR which allows you to do dynamic types whenever you want. Outside of a few gimmicks, you rarely see these used. I've rarely even seen them for quick prototyping, because generally you mess around with using them for prototying, then the first time they go bad, it's really obnoxious, and you realize you're compiling the code and writing function signatures anyway, might as well save the time later and do it right the first time. Then there's the whole tooling aspect of trying to mix type systems. It's different lifestyles. Dynamic programmers aren't going to start compiling their code to run it, static programmers aren't going to switch to a language with weaker tooling around the IDE-ish features, which are mostly built on the type system. My conclusion is this: New languages should all be statically typed, because we shouldn't need new languages at all. We should be fine. The reason we need new languages at all, is because the trifecta of C++/Java/C# basically encompassed the entire statically typed world, but they're all infected with this fully overblown OOP obsession, and the null pointer bug--which newer languages have fixed, through more static typing. Basically we need to replace those languages with similar ones and then just stop making languages for a few decades, until whatever we're doing now looks as dumb as OOP and null pointers. In the long run, Go/Swift/Kotlin/Rust will take over the statically typed world and it's going to be great.
- jugg1es 9y agoIn my experience with growing companies, even business-critical code bases get rewritten within 3-4 years to account for flexibility that the previous strongly-typed system just can't handle. A well designed system uses strong types for the "knowns" but allows changes via dynamic types for the "unknowns". Those are the systems that last.
- z3t4 9y agoWhile the made up graphs might help understanding his reasoning, I think it's way too abstract/philosophical. It's like walking into a dark room making assumptions and arguments based on your belief of what color the walls are.
- jon49 9y agoLanguages like F# give a nice sweet spot between static typing and dynamic typing. It has Type Providers that "generate" code on the fly as you are typing. You don't need to specify all the types, it will infer many types for you. So, you almost feel like you are writing in a dynamic language but you it tells you if you are writing something incorrectly. I would not consider a language to be modern unless it has Type Providers I consider this to be such an essential feature. I believe Idris and F# are the only languages that have it. People are trying to push TypeScript to add it - who knows if it will happen. Many are saying that if you have a dynamic language you just need to be disciplined and write many tests. With good static typed languages like F# you can't even write tests on certain business logic since the way you write your code you make "impossible states impossible", see https://www.youtube.com/watch?v=IcgmSRJHu_8 https://www.youtube.com/watch?v=IcgmSRJHu_8