56 ms·
Things I Was Wrong About: Types
- mlthoughts2018 6y agoThis is the opposite of my progression. I worked professionally with Haskell for 6 years and then Scala for 2 years at the early stages of my career. Static typing is a waste of time that does not facilitate better design, better clarity or safer code. The classes of errors detectable and preventable with static typing are almost never very important, and in dynamic languages you can achieve the same results with lightweight unit tests that are no more effort, and often much less effort, than creating or maintaining type system designs. Type annotations are code and more code is just more liability and more complexity. It really is just that simple. You should strive to write code with the fewest cognitive concepts necessary. Cognitive concepts are the hugest form of tech debt you can have in code, much much worse than repeated code, lack of modularity, lack of test coverage and so forth. Type system design invites running amok not just with all kinds of new cognitive concepts to model every domain problem, but also the code authors are encouraged to use “creativity” when developing these concepts, which leads to poorly factored messes that express the limited view of a set of specific people - often with huge premature abstraction that makes the code excessively brittle (even when it’s claimed to be extensible) and poorly suited to accommodate use case changes or requirements changes. For the past 5 years I’ve moved on to exclusively using the Python ecosystem for system designs. It’s nice since I work in machine learning and no ecosystem even comes close to Python in terms of ML tooling, but even for backend systems and web service designs around the ML product my team creates, using Python has been pure joy in terms of easy development cycles, easy ability to write less code, easy ability to achieve high safety and reliability, easy ability to trade off safety as a resource to accommodate sudden business requirement changes. I can sincerely say across the board programming large backend systems in Python has been more pleasant, easier to design, read, understand and maintain, easier to extend, and led to safer, more reliable delivered solutions than any of the projects I worked on using Haskell or Scala (even when working with those languages in mature organizations that had very seasoned, veteran functional programming experts establishing in-house development practices). Now that I’ve transitioned through senior & staff engineer and became an engineering manager, my perspective over the years has come to endorse dynamically typed languages as vastly superior tools. My experiences with Haskell and Scala just lead me to believe Python is strictly better for large system design.
- dpc_pw 6y agoLet me guess. You probably worked in small teams, mostly with code you co-wrote your whole carrier. You literary compare 3 languages that you happened to use and think that all there is to know about this argument.
- mlthoughts2018 6y agoNo, the Haskell job was in a large financial service firm with a huge investment in Haskell. Many people on the team were even experienced with GHC compiler engineering. The code base was very large and cross-org. All the other jobs have been in large ecommerce firms, again with large codebases cutting across the org, and separate pockets of “small project” development here and there. I also have many years of experience in C and C++, both of which are solid. I especially like writing systems in C because it’s easy to make it module oriented, and static typing doesn’t need to have anything to do with concept or domain modeling, yet you still can occasionally sprinkle it in with simple structs. I like C++ without classes or exceptions, but the language outgrew that way of using it. The best approach I ever saw to using Haskell at scale was to severely disallow any complex type system feature, like even disallowing lensing or custom type classes. Just ruthlessly stick only to basic language features and module oriented design. When you make your own data structures, never generalize them to inherit functionality through type classing, rather always rotely splay out a new module of all the functions and behaviors for operating on that data structure. Do not seek to endow it with any type of compositional behavior besides very basic plain function composition (eg no monadic behaviors).
- dpc_pw 6y ago> The best approach I ever saw to using Haskell at scale was to severely disallow any complex type system feature, like even disallowing lensing or custom type classes. Just ruthlessly stick only to basic language features and module oriented design. I agree. It's not unlike what you can do with reflections and other dynamic features of dynamicaly-typed languages. So it's not a problem of static typing itself. It's a problem of taking a feature of the language and strangling the code with it. I had to do some refactors of JS code where everything was a shapeless objects with random fields, as the language doesn't even nudge the developer into considerations like keeping consistent "shapes" of data. Had similar experiences with some Python code, where I had to fight both data types fuzziness, reflective-features inventions (hello __getattr__!) and OOP over-abstracted nonsense at the same time. One way or another, in larger teams/projects dynamic typing just doesn't scale. Type system works like a most basic documentation / developer aid / consistency encouragment, even if it is pushed into complexity nightmare. I don't think I've ever even seen a reasonably well working large project in a dynamically-typed language... IMO, static typing gets blamed for problems that are usually caused by OOP: complexity caused by needless abstractions (mostly inheritance taxonomies).
- nlitened 6y agoIt looks to me as if people who started with dynamic types discover static types after many years, and vice versa. There’s a zen koan about it, I am sure.
- echelon 6y agoI followed a similar trajectory. Types were the bane of my early career. Hideous, extraneous. But really, they're the light at the end of the tunnel once you've worked your way though the dynamic / weak typing minefield. It took me a lot of Python, Javascript, and Ruby for me to get there, but now I'm way more comfortable on the other side. The correct type system is actually way more expressive than not having strong static types. Sum types let you combine multiple return types elegantly and not be sloppy. Option types remind you to check for an absent value. Static types let you refactor and jump to definition quickly and with confidence. Your interfaces become concrete and don't erode with the sifting sands of change. As an added bonus, you don't need to precondition check your functions for type. Types are organizational. Records, transactional details, context. You can bundle things sensibly rather than put them in a mysterious grab bag untyped dictionary or map. Types help literate programming. You'll find yourself writing fewer comments as the types naturally help document the code. They're way more concrete than comments, too. With types, bad code often won't compile. Catching bugs early saves so much time. Types are powerful. It's worth the 3% of extra cognitive load and pays dividends in the long haul. Before long you'll be writing types with minimal effort.
- NicoJuicy 6y agoThe incoherent thinking I see with some people even in typed systems, would make me very scared to let them do the same in dynamic ones.
- ooobit2 6y agoNothing good comes easy. The dozens of hours I'd spend staring at 26 lines in R just trying different ideas to shorten/optimize/improve clarity, and that wasn't something I needed to sell that someone else would depend on for business or personal use. But I can relate to the pressure to deliver quick results. I found myself burnt out when working on a forecast model around three years ago. The constant "how's it goin'?" tore my attention away from the work, and I'm still convinced I could have delivered a better result. So, in a way, I agree. In another, I understand the other side of the issue, and I think there are so many less time-intensive tasks going on around engineering that there's often little awareness that something like refactoring a class for better efficiency pays in smaller but compounding ways long-term, with most of the time cost and perceived opportunity cost being immediate and short-term. It's still worth it if you really do the math on the long-term benefit.
- TooCreative 6y agoI code without types. My "proof", that types do not pay for themselves goes like this: Every time I encounter a bug (during coding, testing or in production) I make a note what type of bug it was and how it could have been prevented. Types are way down on the list of what could have prevented the bug. Especially for production bugs, which are the most important of course. It is so rare, that a bug could have prevented by types that I can say with confidence that they would have been a net negative. Talking about which tool can prevent the most bugs, integration tests win by a large margin. The reason is that most bugs are conceptual. Like "Oh shit! We have allowed people to tag items as duplicates of other items. And we have a function that traverses the list up to the original item. But now this new feature over there had a bug where it marks the last original as a duplicate of another duplicate and then when the traversal function in that other module is used, it ends up in an infinite loop". Another example of a popular bug category: The code contains assumptions about the environment that do not hold true. For example PHP's mb_strtolower() will not always create the same string as MySQL's LOWER(). It is very rare and only holds true for a tiny tiny fraction of the UTF-8 characters. So you might expect them to behave the same until you one day trip over one of those few chars.
- viraptor 6y agoCan you share the tally? I wonder about the categories you used.
- AaronFriel 6y agoGiven that you don't code with types, how are you certain which bugs you could have prevented? I'd be curious to see this list. Is it anecdote, anecdata, or is it a spreadsheet you have somewhere?
- benjiweber 6y agoI find the value of static typing to be more from increasing the ease of exploration and understanding of a codebase than preventing bugs directly. The constraints on how the code you're reading could be being used making building a mental model faster. Not to mention the tooling built on top of the typing that can help with exploration.
- charliesome 6y agoAn interesting insight I came across a little while ago is that for mainstream, industrial languages, this way of thinking about types is relatively new. It's not that we're seeing the pendulum swing back to types, it's that we're discovering them for the first time! In earlier typed languages, the types weren't there for reasons of soundness or productivity at all. The types were there for the compiler alone, as the compiler needed them to know which machine instructions to emit for various operations. Types were just a cost imposed on programmers. Once computers became powerful enough that we could afford to spend cycles and memory making these decisions at runtime, dynamic languages became viable and we saw industry shift over to them, except in domains where dynamic languages still weren't viable, or where existing codebases or ecosystems made it not economically viable. Fast forward to the present and decades worth of type theory knowledge is finally filtering through to industry in the form of languages like Rust, TypeScript, Swift, Kotlin, and others. For the very first time we're embracing types for their soundness and productivity benefits. This is an exciting new era.
- bjz_ 6y agoAs a bit of a nit-pick, it's not _that_ new - see languages like ML, SML, OCaml, Miranda, Haskell, Coq, etc. that combined the notion of types from programming languages and types from mathematics. It's more that it's only recently that _industry_ has been learning about it. That said, I definitely think you're right to point that this is a new thing for industry, and not just a swing back to the idea of types that were previously mainstream in industry. I'm excited too!
- asiachick 6y agoI feel like new features of popular typed languages have also helped them catch up to dynamic language it terms of ease of use. Go back before C++11, without "auto" writing generic code sucked! Callbacks without lambda closures also sucked. I'm sure someone will point to some 40 yr old language that had this but those languages weren't popular for whatever reason. var got added to C# in 2007 and it took more releases to let it be used in more places. Apparently added to Java much later. I'm sure someone will give me a good example but for example std::sort in C++ before closures in C++, if you want to sort one array by another, for example you have an array of indices and an array of values and you want to sort the indices by the values, before closures I'd argue this was fairly painful unless you resorted to global variables or copying all of the data into some intermediate format. You'd end up having to write or generate a class with a sort function solely for the purpose of being able to pass in a member function to sort that could access the values. Today it's trivial because you can write a lambda that closes over the values and pass the indices into sort.
- orobinson 6y agoThe heuristic I use for choosing a statically typed language vs a dynamically typed language for a task is whether or not the code will sanely fit in a single file. If that is the case, then that means I’ll probably be able to keep the structure of the code in my head and therefore I’ll be able to get by with a dynamically typed language. However, once the code starts to span multiple files, typed method signatures in a statically typed language are invaluable. It sucks having to navigate a codebase with tens of thousands of lines of ruby or python code trying to work out exactly what structure of object can be passed to the method you’re working on.
- seanparsons 6y agoTypes for checking things are correct is really important which is what this talks about. For me though they really come into their own when those types then help to eliminate boilerplate. Haskell's foldMap function is my classic example of handling the accumulation of a result where it does the hard work based on the types. Idris goes even further by supporting the ability to infer obvious code for your code editor like handling each case in a sum type.
- TurboHaskal 6y agoHaving started out with Pascal and C, I thought I hated statically typed languages as well until I got exposed to SML and Miranda. I guess Rust or Swift have the same enlightening impact to people coming from Java or Go and I'm glad such approach is finally hitting the spotlight, even if a bit hampered. That being said, and as much as I see the appeal on those and hoped that stuff like ATS or SPARK were more prevalent, for me they lead to dull, boring code bases. Which is great! But when I look back on my career, the most fun I had, the craziest abstractions, cool hacks, the code I'm most proud of, it's the one written in dynamically-typed on untyped languages. And here I'm talking about some flavor of Assembly, APL, Lisp, Forth or Smalltalk. PHP, Python and JavaScript and similar scripting languages just don't cut it for me.
- rwmj 6y agoYeah the article is just "hey, I discovered SML!". I've been using SML, Haskell, then OCaml since the early 90s and the benefits of (proper) types and type inference have always been obvious.
- donatj 6y agoI hated types in college, I thought they were a huge waste of time, and on their way out. But over the years that opinion shifted. I got experience with the actual types of problems we would see. Again and again runtime errors in production, usually from type issues. This really pushed me to invest my time into static analysis tools, and static analysis tools work best when types are at the very least annotated. This was an lead in to compiled typed languages where these types of runtime errors are rare if not impossible. As someone in a similar boat, I feel still like it's more fun to knock out a really quick prototype in an untyped language. For something I actually have to maintain and build tests for, a well typed language is absolutely preferable. I used to quip that no one could build maintainable JavaScript, and I enjoyed writing JavaScript, but now with TypeScript I think it's largely doable. I think what really changed in me is my desire to knock something out quickly was replaced with the desire to have stable software where components could be built well from the get-go and not need modifications for years.
- Toutouxc 6y agoIs 'Maybe Haskell', mentioned in the article, worth reading? Or can anyone recommend a similar book of the 'just enough to be dangerous' kind on Haskell or maybe Clojure?
- tom_mellior 6y agoI don't know about Maybe Haskell, but you can give Real World Haskell a try for free: http://book.realworldhaskell.org/ http://book.realworldhaskell.org/ I found it a pretty good introduction. Unfortunately at some point it devolves into typical Haskell "how can we turn this clear, readable three-line function into a two-line function by peppering it with obscure operators".
- christoomey 6y ago'Maybe Haskell' is a fantastic intro to using types and why you might care about them. It's focused in scope and really meant to give you a taste of some functional ideas and a bit of Haskell, and in that effort it does a great job. Also, you can't beat the price ($0). If nothing else, probably worth browsing through to see if something resonates with you.
- chriskrycho 6y agoObviously I’m partial because of my history with the book, but having read a bunch of other introductory Haskell materials, this one is still my favorite. It’s my favorite in part because it doesn’t try to teach you the whole language, it just gives you a taste of some of its powerful abstractions, walking through them with just the `Maybe` type. I read the whole thing on a plane flight, and reread it on the flight back.
- filoeleven 6y agoI learned Clojure by reading Clojure for the Brave and True and can recommend it as a good intro. It helps that the language itself is simple and consistent. You can get remarkably dangerous with only a few hours of study. https://www.braveclojure.com/ https://www.braveclojure.com/
- jgilias 6y agoI once told a JavaScript guru colleague of mine that I was spending my free time dabbling in Haskell. His response was 'lol, why would you do that?'. His point was that spending time learning things that you're not going to be using directly any time soon is a waste of time. My point was (and still is), that learning such things opens up a completely new way of thinking about problems and potential solutions.
- quickthrower2 6y agoDoes he use Redux by any chance :-)
- quickthrower2 6y agoOh, not popular. To clarify the joke being Redux was inspired by Functional Programming.
- loup-vaillant 6y ago"Never learn anything you don't see immediate use of". Such short term thinking could explain why dynamic typing is so appealing: simpler implementations, more possibilities than most mainstream static type systems, while requiring basically no learning at all.
- wccrawford 6y agoMy experience matches yours. Every time I learned a new language, I gained a new understanding of a different way of doing things, and I was able to bring some of that understanding to my daily job's language. It's absolutely made me a better programmer. I didn't just study those languages for nothing, though. I always had a purpose in mind for them, with the possible exception of Ruby which just seemed neat.
- mumblemumble 6y agoLimiting what you learn is, by definition, self-limiting. On the one hand, that's a useless truism - we can't learn everything, so you do have to pick and choose. On the other hand, I still find the framing useful, because it reminds me that, in a sense, the decisions about what not to learn are more impactful. To the example of programming languages: Only focusing on perfecting my skills at the tools I currently use would leave me less able to understand the limitations of the tools I currently use. And would limit my ability to take my career in new paths where I might have a need to use other tools. On the other hand, learning every single new thing might distract me from properly mastering my current tools, or might eat up so much of my free time that I'm effectively spending all my time thinking about work and never recharging my batteries.
- raverbashing 6y agoYeah I agree most of the pain of types comes from the ways they're implemented (especially in early C++/Java etc) Hence my beef with them. PyLint (as an example) can deduce and type check your program for you. Why do I need to annotate the types for every single thing? Python is not exactly a weakly typed language if you go down the details. So if the compiler knows (or even worse in the case of Java: the IDE knows), why do I need to tell it that? Then you end up with the cases of several prototypes for the same function for things that are essentially the same. I can understand type annotations for documenting interfaces. Those make sense.
- choeger 6y agoFor me it is somewhat different: I always used typed languages and occasionally have to read and improve untyped code. I must admit, I feel half blind in the latter. When debugging a python web service, trying to figure out the control or data flow, I very often scratch my head and wonder "what is this thing"? This applies both to library functions and code from colleagues. Sometimes it feels like untyped languages are write-only languages.
- christophilus 6y agoThis is my biggest gripe, too. Discipline about commenting helps, but only so much. In my case, I have Clojure spec or the JavaScript equivalents at the important boundaries in my code. That makes this issue much less painful and also solves a few other issues to boot. To be honest, in more advanced type systems, I’d ask: “What is this” only to be shown a convoluted type signature. I then put a println or breakpoint in there just like I would with a dynamic language and poked around.
- dynamite-ready 6y agoTypes are useful, but they are currently trending, so now, they might often be forced into situations where they might not be needed. Programming languages and their type systems are tools, at the end of the day. Occasionally, an overwrought system of types will slow you down, or quite possibly make simple changes impossible. On another day, some other type declaration could save you hours of debugging, or speed up your program by orders of magnitude... Simply put, I feel that many Java programs probably could happily be replaced by Python or Node JS. On the other hand, some safety critical UI projects (or at least, some key portions of them) absolutely would benefit from Typescript or Elm. I wish there was more discussion about when each is a better fit, rather than talking about how much worse A is than B.
- jondubois 6y agoType hype is real. It almost seems like job-creation propaganda at this stage. When I judge things, I look at practical outcomes; and the fact is that I produce better software with more features within the same timeframe if I use JavaScript rather than TypeScript and the product in both cases is equally robust. This has been true for me both independently and as part of a team. With JS, I can write more code and more tests within the same amount of time and there is no drop in quality. I'm very surprised that nobody else seems to be experiencing the same thing. I've been back and forth many times between the two paradigms and for me it's clear as day.
- rswail 6y agoSorry anecdata isn't data. You might be able to write more code in terms of LOC but you're also writing tests that a strongly typed system wouldn't need. You don't know that your code is "equally robust". You don't know what sort of "drop in quality" you have because you're not using strong types. You are making a judgement that isn't backed by anything other than intuition.
- valuearb 6y agoI switched my Javascript code base to Typescript a few months ago. There is a productivity cost that is declining over time as I get more used to Typescript. But the conversion also flushed out some significant bugs in the JavaScript base. And I only get to work on this code once a week. So when I come back to it I’ve found it’s much clearer how it works and I get productive much faster. I will bet any coworkers who have to work on your code wish it was in Typescript.
- fizixer 6y agoI was wrong about types too. I used to think after I had mastered half a dozen languages, I should start spending time on typed languages, maybe eventually learning type theory, Haskell and what not. Now I focus on things that matter: deep learning, AI, and robotics.
- chousuke 6y agoFor my use cases, the vast majority of errors with dynamic languages boil down to being able to run scripts that have undefined variables; I'm prone to (mental) typos, so if I had a dialect of Python that failed before runtime when undeclared references exist, I could probably cut the number of iterations I need to arrive at a working script by at least half. I've never found a valid use case for allowing undefined references, though I suppose it does make the language implementation significantly easier. Writing tests is not really a solution either. Tests are also code and suffer from the same problem.
- christophilus 6y agoAt least in JavaScript, these are flagged by a linter. I imagine Python has a decent linter and code editor integration of said linter?
- petters 6y agopyflakes finds these. It has virtually 0% false positives and runs extremely quickly. Run it on save or in a git commit hook. (I agree that they should be a syntax error though)
- samanator 6y agoWould be very difficult (or impossible) to make this a syntax error since exec() Modifies the global scope
- samanator 6y agoPycharm warns you when that happens. I'm guessing they are using a combination of the abc module (to parse the abstract syntax tree) and some linter that can be found on pypi. Would a validator that runs before your main python executable solve your problem?
- samanator 6y agoOops I meant the ast module, not the abc module
- diminish 6y agoTo play against the current wave, and give a contrarian pov: I'm grown up with statically typed languages from C/C++/C#/Java and later and didn't know about dynamic languages till recently. 1. Which types are we talking about? - In earlier static-typed language, the processor-based types `uint64` looked very strict, optimized the code for hardware architecture. - Having mathematically and ontological correct types is one approach `integer`/`float`/`string`/`datetime`. - Each type being well defined and each object-class being used as type is another strict approach. Look at the types of Rust and Kotlin and see the cacophony of decisions made: - Rust https://doc.rust-lang.org/reference/types.html https://doc.rust-lang.org/reference/types.html - Kotlin https://kotlinlang.org/docs/reference/basic-types.html https://kotlinlang.org/docs/reference/basic-types.html 2. When you want to implement a method which applies to multiple libraries, you end up writing `fooString`, `fooInteger`, `fooDatetime` etc (or foo(String), foo(Integer)) etc. DRYing is too hard. So you end up writing 10x more methods 3. No you don't avoid `null` checks at all. 4. Generalizations are harder to implement. 5. Interfaces are uglier compared to dynamic languages. 6. The code becomes less readable, not concise and verbose 7. Every new and old typed language is less elegant compared to the dynamic. Look at typescript vs javascript, typescript code is ugly, verbose, non-readable at all.
- inertiatic 6y ago>2. When you want to implement a method which applies to multiple libraries, you end up writing `fooString`, `fooInteger`, `fooDatetime` etc. DRYing is too hard. So you end up writing 10x more methods As discussed in the article, you want a sum type here. >3. No you don't avoid `null` checks at all. Entirely language dependent. >4. Generalizations are harder to implement. For some definition of harder. Harder to implement, causing you to think harder about what should be allowed under these generalizations, leading to less bugs, leading to things being... easier to actually implement in the long run. >6. The code becomes less readable, not concise and verbose. Since you only recently got into dynamic languages, just wait till you try to get into a large codebase without types. Where everything basically devolves into containers of arbitrary things that you don't know what they contain until you've gone through the thing with a debugger. Maybe your day job becomes more interesting that way. Making CRUD apps is admittedly boring, but this isn't in my opinion the way to keep one's self on their feet.
- adnzzzzZ 6y agoI don't really see most of my code being improved that much by types and I also see a lot of extra complexity that people in the sphere I am (indie games) have to deal with when using typed languages. It just doesn't seem worth it. When you have to spend a lot of time fighting your language, and handling numerous extra concepts that don't exist in an untyped language because they don't need to, it feels like the people who swear by typed languages that they simply like creating extra work for themselves as a way to avoid doing what's actually needed to be done, just because they want to feel productive. I also suspect that a lot of this has to do with people's personalities around the concept of borders. Some people like well defined borders in general in everything they do because they approach life from a more procedural perspective, and for procedures to work they need things to be in the right boxes and in the right places. While others prefer borders to be undefined and more free-flowing because more information can pass through concepts and that allows for a more unstructured design process. It only puzzles me that there's so much energy in indie game development for highly bordered programming environments (i.e. all the energy being put into gamedev Rust libraries) when indie developers tend to be people who value borders less, as do all creative types. But I guess people really like types...
- sideshowb 6y agoMaybe it's a case of problem complexity. I think of types as a tool to help cope with certain things. If you're building a garden wall you probably don't need CAD. For a 747, you probably do. Though aircraft predate CAD so it's clearly not impossible to do without. I dislike types in 30 lines of python because they're unnecessary complexity. I like them in 10000 lines of c++ because they do some of the thinking on my behalf.
- i6ruce 6y ago> I dislike types in 30 lines of python They are already there you just don't want to acknowledge them. You can build the same prototype in strictly typed language just by sticking to some primitive types like int/string and type inference, and the progress toward something more complex as your prototype grows. I personally prefer to use types right away, so type system can guide me further and show me when I'm assuming something in a wrong way.
- cel1ne 6y agoTypes are important and necessary. Can you skip them in a typed language? Yes, just use any, Object or whatever the equivalent. Can you add them to an untyped language? No. They are not needed anywhere. But I argue that especially JavaScript module-systems would have benefited greatly from them. A million lost hours in fixing obscure "undefined is not a function"-errors from output of highly dynamic pluggable build/transpiler-systems like webpack, requirejs, babel, buck etc. could have been avoided.
- nlitened 6y agoJavaScript is not untyped, it’s dynamically typed. The types are still there, they are just not enforced at compile time.
- Ericson2314 6y agoNo "dynamically typed" is an oxymoron, and untyped or "unityped" is correct. Please read https://existentialtype.wordpress.com/2011/03/19/dynamic-languages-are-static-languages/ https://existentialtype.wordpress.com/2011/03/19/dynamic-lan..., the classic take-down of this mistake.
- cel1ne 6y ago"They are not needed anywhere." -> This should have been "They are not needed everywhere."
- AnimalMuppet 6y agoNo, they are not needed anywhere. Anything you can write, you can write in an untyped language. That's a pretty strict definition of "need", though. There are many situations where types can help, even if they aren't absolutely needed.
- hohohmm 6y agoThe benefits of types is not something to be discovered, but something that's taught in school with very convincing arguments, if not too much zeal. It's interesting to see this kind of post. Not to be sarcastic about the late discovery of typed goodness, but the fact that this is not already a concensus in the engineering world.
- christophilus 6y agoIt’s not a consensus because many of us have found that types are not the panacea we were taught. Erlang is a fantastic language, and it’s arguable that types would not improve it, but rather hinder some of its better features. Same is true for Smalltalk and various lisps. I think there’s a place for various approaches to types.
- orwin 6y agoAll lisps I used could be statically typed, I think? Does elisp used typep? For small projects, hacks or emacs macros types are not useful but the possibility of adding types is there. [Edit:and it's useful when your finite state machine grows to much]
- shortercode 6y agoInterestingly quite similar to my own progression. I think working in modern typed languages ( Rust, Swift, Typescript ) is what primarily changed my viewpoint in a way that C and Java just couldn't. In the last year I've transitioned from full time JS development to full time TS development and have been pleasantly surprised how easy the transition was for my personal projects. Previously I had been quite adamantly against TypeScript; seeing the type system as an unnecessary level of complexity given I already structured my code in quite strict ways. In most it helped me find 1 or 2 small errors, but it certainly helps reduce the amount of time I spend verifying the behaviour of code. It definitely has its flaws, but most of them are linked to its compatibility with JS and I don't think they can be resolved unfortunately.
- christophilus 6y agoI was a statically typed fanboy for most of my early career. C# and later F# were my daily drivers and still hold a fond place in my heart. More recently, I learned TypeScript and a bit of Haskell and Rust. However, I think dynamic languages have their place. Most of my server side code involves parsing one string and transforming it into another (JSON to SQL or the like). Something like Clojure spec is really, really useful for this, and beyond that the remaining code doesn’t really materially benefit from static types. At any rate for my typical web application, I now prefer dynamic languages, which is something I never thought I’d say. One last thought: soundness is just one variable to optimize for, and it’s not as important as I once thought. For most parts of my application, rough edges are not a big deal. For the really important stuff (like payments), I always write tests and also do a fair amount of manual testing. And for that stuff, the bugs are almost always logic bugs that types wouldn’t have caught.
- edwinyzh 6y agoHow about a language that supports both strong typed data type and dynamic data types? Not sure about other language, but Free Pascal and Delphi support both of them.
- Ericson2314 6y ago> Most of my server side code involves parsing one string and transforming it into another But this is the real problem. It's a huge failure that so much programmer effort goes into writing the same broken marshaling code over and over again. It's unproductive, boring, and if you believe in http://langsec.org/ http://langsec.org/ also the major source of security issues.
- mantap 6y agoA good static type system is better than dynamic typing. But, dynamic typing is better than a bad static type system. A bad static type system will slow you down, forcing you to appease its irrelevant complaints, and pervert your code into a form that no sane programmer would choose to write it in, if it weren't for the type system looking over their shoulder. I won't mention any names, but suffice to say such languages exist. On the other hand, a good type system recognises that its goal is to allow the programmer to write code first in the form that makes sense to them, and then be expressive enough to describe it.
- jariel 6y agoPeople often think about coding, but that's generally a small piece of it. Typing is a form of structure, and especially a kind of documentation. When encountering APIs of various kinds 'typing' is part of how they are expressed. It's hard to build large monoliths without typing. When working with 'wide scope' problems, when the typing is more oriented towards the data, that's another thing altogether, which is why I think for many systems untyped JS and Python works well enough there. What most typed systems lack is a fluent way of mapping to 'data types' which are often external to the system, or at least externally defined.
- dpc_pw 6y ago> It's hard to build large monoliths without typing. It's hard to build anything larger. In a microservice architecture one of the best things one can do is to define machine-readable schema (which is just a way to "type" RPC calls and messages) for all APIs/messages/events, and then auto-generate generate client code from it. Most of the people who oppose typing must have been working on tiny projects, in small teams where they were co-authors of most of the code.
- lolive 6y agoStrings, integer and boolean are enough to model the world. Period. Ps: oh, and 640k should be enough for everyone!
- jondubois 6y agoFor me it was the opposite. I started out with dynamically typed, then switched to statically typed for many years, then I realized that types were almost worthless (and even harmful in some cases in terms of how they influence design/architecture) and I switched back to dynamically typed and never looked back. Nothing beats good testing and good architecture design.
- andybak 6y agoOne note of caution. There's a pleasure to solving problems that arise from type systems akin to solving Sodoku puzzles. It's intellectually satisfying and feels like productive work. I sometime worry that a lot of the overhead and baggage that type systems sneak into coding are hidden because it's fun to resolve them. I'm still on the fence about types. I love them when they help me but I find myself generally writing more boilerplate and less elegant code than I can sometimes write in Python. My typed language is C# so I do have type inference (although not the most advanced). I don't have Union types. My IDE does warn me about potential nulls. So I've got 50-75% of the things listed in this article. And I'm still not 100% sure there's not a hidden cost that's quite hard to define.
- dpc_pw 6y ago> There's a pleasure to solving problems that arise from type systems akin to solving Sodoku puzzles. IMO, That's not type system but OOP. Where I have problems with types is usually due to class hierarchies, and developers trying to invent "beautiful" taxonomies and abstractions for the sake of abstractions. I guess generics sometimes come as a cludge too, particularly if they are combined with the above OOP issues. In a typical bussiness/app code if you don't use inheritance or keep it to minimum, and use generics where they belong, static typing is rather mindless. "This needs something that implements interface ServiceA, and a string" and then a bit of familiarity with handling collections and "Options". From my experience, it's only sudoku puzzles if you (code author) make it so. Not very unlike the opposite version when people go very wild with abilities of lack/dynamic typing.
- JackMorgan 6y agoTypes are controversial because we can't measure engineer productivity. Full stop. I see people on here arguing that they are faster one way or the other, yet we have absolutely no empirical evidence for such a claim. What makes it more complex is that "fighting with types" often takes one out of the flow in a different way than usual progamming challenges. Since it's unmeasurable, we cannot see the effect of productivity relative to team size, feature churn, product timeline, unit test discipline, etc. For example, I'm completely convinced types add significant productivity increase to any team of more than two programmers. Likewise types are a net productivity improvement to software that has to be added to multiple times in a year. If it's a one-off write and throw away, or tiny team, it probably doesn't help as much. Also if it's a big team, but with highly siloed developers, likely doesn't add as much value. I think fighting with types FEELS slower than it is, like how dealing with a car that doesn't start immediately or a street with a lot of stop signs feels slower than just getting out and walking, despite the empirical evidence to the contrary. However, these beliefs of mine are BACKED BY ZERO EVIDENCE. Just let that sink in. We all are arguing about a topic that inherently cannot be measured. We should be trying to tackle the measurement issue first, rather than just keep yelling about chocolate vs vanilla forever. When all we have to go on is feelings, we get people arguing which is better: cars or bicycles, without any discussion or facts about top speed or total distance. The cyclist is always going to talk about wind in their hair feeling like they are going so fast, or how it slows them down to look for gas stations and just stand there pumping gas when they could be making progress pedaling. And to stretch the metaphor even further, there are plenty of environments when a sedan is slower than a mountain bike, and plenty where they are the same. I suspect all this is true with types, yet we have absolutely no way to know. For all we know, the "collective wisdom" of types might be exactly backwards, because basing engineering decisions on feelings rarely correlates to empirical results.
- fulafel 6y agoI think from an empirical mindset we have to grant that the lack of evidence probably means there is no significant advantage. Because there have been lots of studies, we can't simply say we don't know if there's an effect, or we don't know how to measure it.
- IshKebab 6y agoI don't understand why he thinks Typescript still isn't worth it, when all of his points are issues in JavaScript that are solved by Typescript.
- chriskrycho 6y agoI think you misread the post! I very much like TypeScript, am a core contributor to the TS work in the Ember.js ecosystem, and am actively involved in efforts to make TS a first-class supported language in my day job!
- IshKebab 6y agoOh, I was referring to this: > If you talked to me about types in programming languages six or seven years ago, you would quickly have learned that I was not a fan. > I was working with Python and JavaScript and simply didn’t miss types at. all > I understand why I thought that types were worthless from 2012 – 2014. In fact, for the specific languages I had used up to that point, I continue to think that the types don’t really pay for themselves.
- chriskrycho 6y agoAh, I can see how you got there. I was not working with TS then; like most people I didn’t yet even know it existed. At the time, I preferred untyped JS and Python to typed C, Fortran, Java, C++.
- aazaa 6y ago> Type inference: because having to write out every type, however obvious, is an incredible waste of time. Person me = new Person(); is ridiculous. let me = new Person(); may seem like a small improvement, but spread over the body of an entire program and generalized to all sorts of contexts means that type annotations become a tool you employ because they’re useful — for communicating to others, or for constraining the program in particular ways — rather than merely because the compiler yells at you about something it should know perfectly well. Type inference was a major revelation to me as well in Rust. I was reluctant to learn the language because of my experience in Java with its high ceremony everywhere, mostly due to lack of type inference. The first thing I noticed with Rust was type inference. It gives the entire language a distinctly high-level, almost scripting language feel - modulo ownership.
- aembleton 6y agoYou might enjoy Kotlin. Type inference, with full compatibility with Java libraries and ecosystem. Similar to Rust, you can just write `val me = Person()`. No need for the new keyword.
- eru 6y agoThough keep in mind that not all type inference is created equal. Ie what you find in Haskell or OCaml is much more powerful than what eg Go gives you. (In Go type inference only works 'forward'.) (I don't know enough about Kotlin to know what kind of type inference it has.)
- edem 6y agoI love Kotlin. I also love Typescript. I'm yet to try Rust, but I'm positive that I'll love it as well. They are all born to solve the same problem I think, only from a different perspective. I use Kotlin every day and the more I learn the happier I am. I'd never go back to Java if I can help it.
- jenscow 6y agoPersonally, I prefer the type names to be at the start of the line, so I don't need to scan to the end of the line (or guess based on a function name). But I agree, it's a waste to type it all out. So I use an intelligent IDE that reduces the repetitive typing: So typing `Person.var` gives me `Person person = new Person();` or typing `Person person = ` will suggest `new Person()` Sure, it doesn't look as appealing when creating an new object, however I get a better information when you've written something like: Person me = something.GetOwner(); rather than: let me = something.GetOwner();
- dwaltrip 6y agoOff-topic writing feedback: use less italics. Readers are good at figuring which words are important on their own :)
- chriskrycho 6y agoExtremely fair. I go through phases where I over-emphasize all the things, and usually a second/edit pass helps clean it up. I actually went through and removed a ton of them from the post itself, just because of this very comment. ;)
- pavel_lishin 6y agoA lot of people in the comments are saying how they started off in Java, or C, and hated types, but eventually grew to love them. I started off in PHP. It was wild. Anything could be anything. Refactoring was a nightmare. Our codebase was littered with mystery variables like $hold, $hold1, and $holda, which were re-used all over the place. (Granted, this two other problems entirely orthogonal to types.) Then I got a job at a Java place. My god, it was beautiful. I could suddenly know what arguments functions were expecting, even if I hadn't seen them before. I could be instantly aware if I was trying to use the wrong variable somewhere, or pass in invalid data. It was as if someone lifted me out of a dank cellar where I had previously subsisted on whatever mushrooms the rats didn't deign to eat, into a brightly lit dining room full of steak and pastries.
- eru 6y agoApropos PHP: I hate it with such as much passion as the next guy, but I am quite impressed with what Facebook managed to do with Hack! (Including adding lots of types.)
- billisonline 6y agoDon't forget, much of that effort has now trickled down into the PHP language itself. We've long had scalar types for function parameters and return values, but with 7.4 and 8.0 we've added union types[1], nullable types[2], and typed properties[3]. While not a part of the language yet, generics can be annotated with the linting tools PHPStan and Psalm[4], and native support for these annotations is coming to the next release of PhpStorm[5]. Using PhpStorm, I've worked with 100 kloc PHP codebases where almost every type was inspectable. And the language support and tooling are only getting better all the time. 1: https://stitcher.io/blog/new-in-php-8 https://stitcher.io/blog/new-in-php-8 2: https://www.php.net/manual/en/migration71.new-features.php https://www.php.net/manual/en/migration71.new-features.php 3: https://stitcher.io/blog/typed-properties-in-php-74 https://stitcher.io/blog/typed-properties-in-php-74 4: https://phpstan.org/blog/generics-in-php-using-phpdocs https://phpstan.org/blog/generics-in-php-using-phpdocs 5: https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psalm-support-coming-to-phpstorm/ https://blog.jetbrains.com/phpstorm/2020/07/phpstan-and-psal...
- wutbrodo 6y agoI which there was a little more elaboration on _why_ he originally disliked types so much. This perspective is still very strange to me, as the value of types seems self-evident for systems more complex than a script, and I'd like to understand it better. As it stands now, my only assumption is that this comes from the place the author is coming from: people who don't think types are useful are generally coming from a place of ignorance. This feels facile and self-serving though ("people who disagree with me don't know what they're talking about"), so it's more likely that I have a blind spot. Are there any current or former type-haters that can help shed light on their perspective? EDIT: I should note that my production experience is primarily with (modern)C++ and Python, so I don't even have the benefit of more modern static typing systems like Rust's.
- steveklabnik 6y agoI can't speak for Chris, but I can speak for myself. I did the bulk of my early programming in statically typed languages. Specifically, late 90s C, C++, and Java. Then I found Perl, and pretty much went into dynamically typed languages only for the next near-decade. At the time, I felt like the types didn't pull their weight. There was a lot of extra writing, and you got very little benefit for it. Plus, dynamically typed languages had these rich features that just weren't really accessible in mainstream statically typed languages, and so they kind of became associated with each other in my brain even if that wasn't specifically true. For example, seeing stuff like https://www.cs.ait.ac.th/~on/O/oreilly/perl/cookbook/ch11_08.htm https://www.cs.ait.ac.th/~on/O/oreilly/perl/cookbook/ch11_08... absolutely blew my mind, and I had no idea how you could do something like this in the statically typed langauges I was exposed to at the time. It wasn't until I discovered languages that had significantly more powerful features, and had a significant amount of type inference, that I felt the equation changed. The former to give me something better than purely "don't make some kinds of simple mistakes", and the latter to make it ergonomic enough.
- wutbrodo 6y ago> Plus, dynamically typed languages had these rich features that just weren't really accessible in mainstream statically typed languages, and so they kind of became associated with each other in my brain even if that wasn't specifically true. This resonates a lot with me (though as you say, isn't really a typing thing). I work on ML systems for autonomous vehicles, so I switch between Python and C++, and I definitely occasionally start writing some C++ logic in an elegant functional way and realize that C++'s boilerplate makes it less readable than the usually-less-readable naive construct like a loop (eg I'm surprised at how often std::transform comes out looking terrible). Do you mind if I ask about the size of the systems/teams you've worked on throughout this process? My experience with C++ has been in large systems worked on asynchronously by lots of engineers (with strong code review policies in place), and my experience with Python has been everything from moderately-sized systems down to smaller ones down to scripting. The Python case also included work with an inexperienced (and frankly, partially unintelligent) team of engineers, which made the discipline imposed by typing all the more valuable, but I have found the documentation and structure that typing imposes on code to be invaluable in communicating As I said in my other comment, I'm still concerned this is a little facile, but having started my career on C++ systems at Google, I wonder whether I've just set a standard so high for the health of a system that many of those who dismiss typing's value don't understand that those benefits are possible (I'm certainly an order of magnitude better at reading code than anyone my current team, but this is confounded by the fact that everyone else has a weaker engineering background and stronger robotics or ML domain expertise). To be clear, I don't think this applies to you necessarily; your approach of trading off the benefits of ergonomics vs structure resonates strongly with me, and I'd imagine it's even more the case on pre-modern statically-typed languages. What I'm really curious about is the perspective expressed in the OP, which, in the 2010s, doesn't even see _value_ in types beyond perhaps negligible benefit from some compiler checks. Thank you very much for the perspective!
- dustingetz 6y agoHate on types seems to stem from three perspectives I can see: 1. 2000 era Java-likes cause superlinear class complexity explosion 2. 2010-era typed functional programming - Scala stdlib type sigs that didn't fit in a tweet, 7 scala stdlib rewrites and churn related to really figuring out how to even do functional programming in applied domains like crud apps 3. All along, cutting edge comp sci research being presented as the "correct" way to program and you're a normie drooler if you haven't read yesterday's paper and rewritten your stuff onto it
- edem 6y agoI've been using Kotlin (which is very similar to Typescript, the language the author also mentions) to great effect mostly because 2 of those points (type inference and sum types) and something else that's also very powerful and not mentioned in the article: extension functions.
- withinboredom 6y agoI work on the big data side of Automattic, so I tend to work with PHP, Typescript/JavaScript, Python, and Scala, but I also work with C# for fun. When you work with and without types often, you realize that it doesn't matter. Types are great for expressing constraints on the code, but you can do the same thing with conventions in non-typed code. IMHO, type-less provides some resiliency. If you write code for a "string" anything that satisfies "stringiness" will still run just fine. This lets you build types that "trick" the code you're calling, which can be useful sometimes. I think I've abused this capability less than 3 times, but more than once. Mostly it allowed me to significantly change behavior without rewriting huge chunks of core code. However, these were all proof of concepts. Don't get it twisted, working with no types is pretty annoying sometimes. Types, on the other hand, are great for most things, but I do find they get in the way sometimes. It's annoying when you look at the code you're calling and see that it only uses `.x` on a type you pass it, but you have to completely build a type just to create a `.x` on the type you pass in. I once found a NullPointer bug in HDFS with a static type (very strange) and had to work around it doing exactly this. Anyway, I think I'd like Go's approach to interfaces.
- rswail 6y agoUsing interfaces/traits/protocols don't preclude strong typing. If you write code for a type that "has" stringiness, as expressed by a trait, then anyone can build a variant of their types that expresses that trait.
- withinboredom 6y agoYeah, for sure. That's certainly possible, but I rarely see people build for it, at least when it comes to value types like strings, ints, etc. One other thing that I DO like about type-less, is the ability to introspect, for example, in PHP: ``` foreach ((array) $my_class as $property => $value): ``` vs. a bunch of boilerplate and making sure types match up in most strongly-typed languages.
- musingsole 6y agoThose who argue strongly for one method over the other are likely to not understand the one they're against. Which sucks, because if you do know both, there's rarely a reason to have strong feelings one way or another. So, once again the naive but vocal voices get all the decision power. /Too many arguments at work are over dogma and I have to spend a lot of my time reminding people that there are options. That's all. There are options. Your kneejerk response to a problem might be fine -- might be right -- but there are always options.
- rswail 6y agoA lot of people are making comments about how they can code "faster" without types. But for the majority of the code we write, inital speed isn't that important. Understanding the code and maintaining it are orders of magnitude more important for any non-trivial code. Types are not only a way for the compiler to understand your code and impose constraints. They're also your API to other programmers. When they see a sum type, they can understand its possible states. When they see a product type they can understand its possible values. Understanding other people's code is at least half the job of a programmer, whether it's understanding a library or understanding code you have to maintain, or understanding your own code that you wrote 6 months ago. Types help you do that.
- skohan 6y ago> Understanding other people's code is at least half the job of a programmer This was one of the pain-points when I was working more with node.js: the function signature told you nothing - like whether the function would even return or not would sometimes be a mystery. In very, very short scripts you can get away without types (like in a notebook for example), but once a project starts to get even medium size the tiny amount of time you put into writing a type name explicitly here and there is more than made up for by the degree it helps with the structure and correctness of your program.
- bo1024 6y agoThis kills me about python. So many times I cannot figure out what exactly a functions expects and what it returns, sometimes even from reading the documentation! Matplotlib is especially bad.
- carapace 6y agoThesis, Antithesis, Synthesis Types Bad, Types Good, Types are a gateway into sophisticated automation of programming tasks but not a panacea.
- hn_throwaway_99 6y agoI'll add a 4th thing to his list based on my experience moving from Java to Typescript: Nominally-based type systems like Java (where you can only write Foo f = new Bar() if Bar has Foo somewhere up it's static type chain or interface hierarchy) are way more of a pain in the ass than structurally-based type systems like TypeScript (where you can say f: Foo = new Bar() as long as TypeScript determines Bar has all the required fields of Foo). Primarily this makes refactoring much easier because you don't have to necessarily change things up a (potentially brittle) type hierarchy. Instead, you can just add new properties to your type to fulfill the set of properties required on the target type.
- couchand 6y agoThat isn't always a benefit, though. When interfacing with a database schema that uses small integers for ids, I'm all the time defining types like `struct CustomerId(u32)` and `struct InvoiceId(u32)`. It's incredibly valuable that the compiler will not let me mix up a customer and an invoice, even if both of them are 42.
- joshuamorton 6y agoAd hoc and structural polymorphism can coexist. You can define an object that contains a customerid and an invoiceid, and they won't get mixed.
- tasogare 6y agoThis is why interfaces exist.
- piedar 6y agoNominally-typed interfaces are still clumsy in some circumstances. For example, if I consume a library with namespace ThirdParty { public sealed class Foo { public void Do() { } } } and I want to hide it behind namespace MyCode { interface IFoo { void Do(); } } the compiler does not accept ThirdParty.Foo as an implementation of MyCode.IFoo so I must define a wrapper namespace MyCode { sealed class ThirdPartyFooAdapter : IFoo { public ThirdPartyFooAdapter(ThirdParty.Foo instance) { _instance = instance; } readonly ThirdParty.Foo _instance; public void Do() => _instance.Do(); } } which only gets more tedious as the number of methods and implementations grows.
- kobe_bryant 6y agoI'm working on a system where the users supply equations as rules and in a roundabout way we came across static vs dynamic typing. having users have to define each equation and its type (boolean, numerical, etc) would make it simple and foolproof, but add extra work and requires defining each equation separately when a lot of them are just partitioning the space (imagine 30 combinations of x, y and z) so we ended up deriving the type from how its result is being used, but that puts the work of getting it right on the user
- rogerkirkness 6y agoRewriting our app from Node to Go reduced cloud spend by 20x, did not increase dev time, made it much easier to read and grow the project past 5k lines. Literally no downside. If your database is typed on the bottom, and your documentation is typed on the top, you have a type sandwich in every non-script application. Might as well be consistent.
- ir123 6y agoCan you elaborate on how you reduced the cloud spend? Was it the CPU usage?
- christophilus 6y ago20x seems high. Node is within 3x of Go in most benchmarks I've seen like TechEmpower[0]. I'm curious how you got a 20x improvement? [0] https://www.techempower.com/benchmarks/ https://www.techempower.com/benchmarks/
- rogerkirkness 6y agoConcurrency instead of queuing between microservices
- fmakunbound 6y agoStatic types are great for Fungeable Programmer at Big Co. where you can be dropped into a project and it sort of gives you a way to figure out what's present in the code. However, if you need to get somewhere fast, be it a side project where you've only got so much time due to other constraints in life, or it's a product you're trying to get to market first with a small team, then you're not going to benefit from ossifying statically typed languages - you're going to reach for something that's interactive, powerful, and not bogged down in edit/compile/test cycles. You're going to instead reach for something like Common Lisp, Ruby, Python etc. Once you're making $COMFY_DOLLARS_PER_MONTH you can then pass it off to some re-write team, though.
- chriskrycho 6y agoI think this is a false dichotomy. When I’m knocking out something as quickly as possible, I actually prefer statically typed languages. I have some quirks b/c of my particular background (my formative years were a constant mix of C and C++ and PHP and JS), so I often build even “script”-like tools in Rust instead of Python or Ruby or whatever. I find the ability to refactor rapidly is increased for me as I work in languages like Rust, ReasonML, etc. But I also work with and know folks who are absolutely brilliant, who build large systems carefully and slowly… living almost 100% in the REPL of a dynamic programming language. This approach is not the one I prefer, and in fact when I’ve tried it it has kind of driven me batty. But this doesn’t seem to be a function of either competence or context whatsoever (though certainly types do help somewhat in the Working In Any Sufficiently Large Codebase scenario); it seems to be a function of cognitive style.
- deckard1 6y agoI see a lot of comments on HN the last few years that just assume the dynamic vs static debate was settled at some time. It never ended. Static typing merely became trendy because dynamic typing was the trend for many years (Ruby, PHP, Python, Perl, JavaScript). Like all fashion, things that are trendy will once again become untrendy, and the cycle repeats. With that said, it's important to note that type inference is not new. I was doing type inference with Scheme nearly 20 years ago. I believe the reason it never took off in a serious way is because it combines all the downsides of dynamic typing with the downsides of static typing. Types are meant to document code. Without the annotations, you can't look at code and know what is going on. Which, ironically, is the complaint against dynamic typing. In addition to that, you get the pain in the ass of having the compiler always complaining. And because it's inferring types, the error messages are towers of baffling nonsense. It's the worse of both worlds. One thing that never comes up in these discussions is the idea that creating good types is a skill itself. Much like naming variables, if you don't design your types correctly, your entire code base suffers. It's much easier in a dynamically typed code base to "nudge" the data in a certain direction than in a static type system where all types are locked down at initial design time. In addition, certain type systems are much harder to master than others. I've worked with dozens of TypeScript developers and not a single one really knew what they were doing. They were appeasing the compiler and little more than that. There are also plenty of footguns in TypeScript that even TypeScript experts continually forget. I could continue on the weakening of the value of TS (via "any" and "ts-ignore", etc.) and how these completely muddy any sort of metrics one may have on deciding whether types are "worth it" or not (or the fact that such metrics do not, in fact, exist). But that's enough ranting for one day.
- billisonline 6y ago> Types are meant to document code. Without the annotations, you can't look at code and know what is going on With the rise of VSCode IntelliSense/JetBrains code inspection, do you believe this is still true today? The programmer now has easy ahead-of-time access to inferred types that used to become available only at compile time or runtime
- mamcx 6y ago
- deleted 6y ago[deleted]
- chriskrycho 6y agoAuthor here, with a few comments on things that I see coming up through the discussion— 1. This is not a post bashing dynamic types. When I write that I now value type systems, that doesn’t imply or entail thinking that dynamically-typed languages are bad, wrong, etc. I have a preference for (a certain variety of) static types these days, but some of the best and smartest engineers I know have a preference for dynamically-typed languages—and as my conclusion notes, I take that much more seriously than I did earlier in my career. I’m particularly interested in spending time with Erlang/Elixir and Clojure in the future, as both of them take very different approaches to robustness from the dynamically-typed languages I’ve worked with in the past. 2. Folks have asked about what specifically I found lacking in the type systems I encountered earlier (Fortran, C, Java). I alluded to this in the post, but I’ll elaborate a bit. For my part, I found that all of those—really, anything in that line without influences from e.g. Standard ML—required a great deal of the work of a type system without the degree of benefit I wanted from it. There has been some progress here in languages like Java, C++, and C with `var`/`let`/`auto` with inference, and more by adding in closures and the like. But even today, the gap in what I can express and have the compiler check for me between Java and even TypeScript (much less TS, Rust, Elm, Haskell, etc.) is large. That gap is where a ton of the value is, at least for me. 3. Other folks allude to coming from e.g. PHP to C and Java and finding even C and Java’s relatively limited type systems to be a blessing. I can see how that would be the case, especially given Java’s really great tooling for refactoring. I actually worked with C, C++, Fortran, PHP, JS, and Python all in parallel for the first four years of my career (and semi-regularly poked at Java; I had some early-2010s interest in Android dev that never went anywhere), so it was certainly not from lack of exposure that I didn’t find the tradeoffs all that valuable in the type systems of C, Fortran, Java, etc. 4. I strongly suspect that “cognitive style” (for lack of a better way of putting it) plays an enormous role in how one feels about and approaches types. The literature on types is not very conclusive or robust, and while it finds (e.g in studies of TS) that it does eliminate certain categories of bugs, advocates like me would do well to remember that the effects are relatively small and relatively limited even so. And as I alluded to in (1), I know a bunch of brilliant developers who recognize the value of types in principle—who have worked with Haskell or other similarly robust languages!—but don’t prefer them, and from discussions with them it’s very clear to me that we just think differently, and therefore approach building systems differently! 5. I think there are places where not using the best and most robust type system imaginable is negligent: a TLS implementation, for example. But in those areas, I also think that you’d better be doing an enormous degree of testing, and putting formal methods to use, and doing multiple audits, and basically throwing every possible solution at the problem. Same thing for aircraft or spaceships or medical hardware. Your average CRUD app… probably doesn’t need that level of effort, though. One of the problems in any discussions or debates about these kinds of things is failing to distinguish appropriately between the things which are necessary for different domains and indeed which may be better suited for those domains. 6. Finally, a meta-point: I find it entirely predictable, but a little bit sad, that this post blew up here on HN, when I tossed it off in under 15m… while a deep dive on a cutting-edge JS reactivity system I spent 3 weeks writing and revising got far less attention (and I’m sure that goes for many such careful write-ups). I get it: we all have opinions about things like types. But it’s still too bad!
- dboreham 6y agoHonestly I think people who object to typing are lazy and inconsiderate to other people who will need to read use and maintain their code. They often haven't had much experience and haven't worked on large code bases in my experience.
- codygman 6y ago> If you have the option between creating a function which accepts a string (e.g. ID) as argument or accepts an instance of type SomeType, it's better to pass a string because simple types such as strings are pass-by-value so it protects your code from unpredictable mutations What if you work in a language where SomeType is pass-by-value? Would you still prefer the string?
- novok 6y agoI would even assert the amount of typing you get in a language like Java or even C is very useful. I think a big reason why the python 2 to python 3 transition was so painful was a lack of static typing. Unlike other languages where if you update to the new version and get a whole bunch of build errors about methods not existing for a type or this function now returns a different type, you had to run an %80 of the way there migrator who's effects you weren't completely sure about and run your app through your unit test suite. Almost nobody has %100 unit test coverage to approximate what a build statically typed language compiler does, some functions 'worked' anyway due to duck typing and did behaviors that were different than what you were expecting and a bunch of methods returned a slightly different string type that gave more errors, only when you ran the code, each exception at a time. While in a static language you can just run it, and you would of saw all the places where a function now returned a bytestring and deal with them all at once, properly. I've dealt with several breaking change migrations with the swift language, and although annoying, it was tractable and only took a day or two without worries about hidden gotchas. Nowadays my minimum requirements for static types are: - Nullable types (does this type container accept nil or not) - Very basic generics for containers - Typical static typing features Bonus: - Enums with variables (also known as ADTs) The reason why I chose these features specifically is they give you a lot of benefit, but are not actually slow to compile and not complicated to implement for language maintainers when first writing a language. I hope golang has all of them one day.
- Jtsummers 6y ago> I think a big reason why the python 2 to python 3 transition was so painful was a lack of static typing. And I'll add compilation vs interpretation to this. I have, on a couple of occasions, had to update Java or C# code from one version to a much newer version. This meant that deprecated features were often used (more an issue with the Java cases). Thanks to actually compiling the code and the static typing, most of the things I needed to update/change were apparent from the start. This didn't mean they were good "modern" versions of the program, but they were functional and operational and could interact with newer Java and C# code bases properly with only a week or two of effort. The same was true when a library was changed in a breaking way (at the interface level). Of course, you still need tests when semantics of the library change (like it returns the same type, but with different meanings), but that's usually well-documented.
- didibus 6y agoI think a point not often brought up is that Java takes a stance against type inference. It argues that type inference can lead to bugs, because sometimes it doesn't infer the type you meant and makes code harder to read. So explicit types it is. Also inference slows down the compiler and similarly the auto-completion. Now, I'm in the camp where I don't really think static type checkers are all that great. I judge languages as the sum of their parts, and in that way, you can easily rank one statically typed lang above a dynamic lang and yet rank another dynamic lang above both of them. I just bring up Java's stance, because I find it interesting. I tend to find most static type checkers enthousiasts have an internal conflict between static types make for programs with less defects, static types help me navigate my code, and static types are too verbose. See this SO for context: https://softwareengineering.stackexchange.com/a/184183/89630 https://softwareengineering.stackexchange.com/a/184183/89630
- andrewflnr 6y agoJava's stance is flat wrong as a matter of practice. I don't believe I've once had the compiler infer a wrong type in a way that led to runtime bugs. If it did, we would all be rightfully annoyed with that compiler because it would be broken. Once more, for the back of the room: Java does not count as an example of a worthwhile type system. Good types do not increase verbosity.
- didibus 6y agoI can see you disagree on a matter of principle and personal experience. And that's alright. I just think it's as valid an opinion as all the others. There are some who like explicitly defined types of various levels. Those who want it all infered or partially infered, and those who don't want them at all, or want them optional or gradual, etc. And none has been able to make a claim over the others even now years later the debate still rage on. The data doesn't show up. And different people have different experience that leads them to different paths. So I like to think of it more as a personal choice. Like various master chef all have their preferred brand and type of knife, so do developers with programming language and type checkers.
- didibus 6y agoI've been wondering where to fit Rust in my mental taxonomy of typed languages. Normally, types are used to statically type check a program, but with borrow checking and lifetimes, types are used to validate concurrent writes to memory locations. That's a whole different use case. One I find much more useful to be honest. It makes me wonder actually, could you have a language whose types are dynamic to the extent of type errors, but whose write accesses are still statically type checked?
- drummer 6y agoThe design of that website rocks. Awesome typography too.
- chriskrycho 6y agoThank you!
- the__alchemist 6y agoI went through an intermediate phase: Typing is good for complex projects, but not simple ones. I've found even that isn't true: In simple programs, typing pays for itself when the compiler, IDE etc catches mistakes I've made. Maybe I just make lots of mistakes. Maybe people who prefer dynamic typing are more careful/better programmers than I. Personally, I screw things up so often, it's always easier to use typing!
- gfodor 6y agoI’m one of those programmers who doesn’t care about types. Am I coding in a dynamic language without compile type type checking? Great, I lean into it, hand me vim and a good testing framework. Putting me into a big Java codebase? OK, time to run IntelliJ and use automated refactoring to change the code. The type system dictates the style and trade offs so it’s just one more dimension that informs how you deal with the code and write new code. I’m more worried about what I’m working on and why.
- sgt101 6y agoI realized these lessons about types in the first semester of compsci at Uni - no one "taught me" but the curriculum meant that I learned this. It's great that people come to these insights on their own - but it's really clear that this is a very inefficient way of learning.
- chriskrycho 6y agoKind of! But there is also, in many areas of life (and perhaps including this one) a reality that you can't actually learn things truly without going through some of these bumps along the way. The funny thing is, I started out passionately affirmative of the value of types, became disillusioned as discussed in the post, and then came around when I found types that actually did the things that I wanted.
- deleted 6y ago[deleted]
- mengopie 6y agoEveryone have their opinions, that's fine, but who cares. It's a waste of time to write out your opinion or discuss them because they are just opinions.
- bawolff 6y agoSo basically, author likes type systems that are aimed around writing correct programs (haskell and rust) dislikes types when they are an implementation detail so the compiler knows how many bytes to reserve to store a variable (e.g. c). The author didn't really change his mind, he just encountered a totally different type of type system with different goals.
- jeanl 6y agoOne good reason for not caring about types: prototype code. I do a lot of prototyping (trying ideas quickly, not for production). I typically do that in python. In that case, I don't think types would be helping me at all, I can get run-time errors, but I don't really mind, it's an easy fix. I used to have to prototype in C++, definitely not the type of language that's fit for that (if only because it's compiled). Prototyping is best done with an interpreted, untyped language in my humble opinion...
- bobbyz 6y agoComparing languages with types to languages without types is like comparing conservatism to liberalism. Less rules = more change. How much of your newfound liking for typescript can be attributed to 'realizing' it's better and how much of it is simply because you're getting older?
- luord 6y agoI'm having the distinct impression that the top comments in this discussion didn't read the article all the way through. This is the article's conclusion: > And, critically, this taught me to be far less dogmatic about the value of ideas in programming languages and software development in general And yet all the top comments are completely, absolutely dogmatic (or at the very least, far more strongly worded than they merit; presented as fact when they're anything but) repetitions of "arguments" said over an over in that sixty-year-old flamewar. A flamewar that has no ending in sight and probably has no ending possible. There have been studies made trying to answer this particular question: whether static or dynamic typing ensure more or fewer errors. Not only have those studies always been inconclusive, in one case the discussion among the researchers themselves ended up turning into a flamewar. As for me, I'm just as happy working with Python or with Typescript, or with Kotlin or Clojure; somewhat less so with Go or Ruby; and I'm absolutely miserable when working with Java or PHP. Because these are just personal preferences, nothing more.
- valand 6y agoTypeScript, Rust, and working on a huge projects impacted me the same way. Rather than "using types so that things run", I have been encouraging people to ”describe business entities/constraints with types” in some languages. That's a way to get compilers to check half of your business constraints. But, I agree that some types are not worth it, particularly those not separating nullish from its non-nullish counterpart.
- zeroimpl 6y agoI think the usefulness of type annotations is directly related to whether you are using classes. In JavaScript or PHP, it’s usually easy to figure out if something is meant to be an int, string, array or object (yes we’ve probably all done “1”+1=>”11” before, but it’s very rare). But if you are using classes, it’s very useful to distinguish at coding time which exact class an object is. Often you’ll end up with multiple classes with similar sets of properties, and it’s imperative to know which one is being used so you call the right methods.
- MR4D 6y agoGreat article. Chris’s rust podcast often sounds like this article reads and worth the time. I happen to be a Python guy. I don’t get to program every day anymore, and python is about all my brain has room for now. However, I’d love to have optional types and am envious of the Typescript crowd. I wish they would have based it on Python instead. Oh well, one can hope. Maybe one day we’ll have something like it.
- ncmncm 6y agoThere is no preacher like a recent convert. For me, using C++, types have always been expected to do the heavy lifting. A language without sturdy types is a language that doesn't help you; you are left to do everything by hand. C++, like Haskell and, to a lesser degree, Rust, make types power tools, engines of coding automation. Java types, by contrast, do not much for you, and C types are little better than none. If you are new to programming with strong types, you will not reflexively unburden youself onto your types, and continue doing things the hard way. That will feel comfortable, but will limit your reach. To level up, you will need to consciously, and frequently, ask yourself if a type could shoulder another burden. You will know you are succeeding when features you didn't notice you were coding pop up, unbidden.
- nojvek 6y agoWithout types, the complexity is shoved elsewhere (in someone’s head). Types make the inputs and outputs explicit. He is right about a good type system being able to infer and being smart at the same time allow placing enough guards around things to truly express the authors intentions of how things ought to be used. One of the reasons why I am not a fan of golang. It’s type system is not that great. You have to do a lot of hacks and copy pasta. Rust, C# and Typescript get it. Python with its new py3 typings syntax is great but it still needs a lot of work to be able to express things like Union types, nullable types, partial types, Recursive types , conditional types, type transforms, genetics etc. There’s a lot that goes on in a good type system. The balance of letting the user express their problem at the same time keeping errors meaningful and preserving the code guarantees.