31 ms·
This is, IMvHO, such old news that it feels... weird to still read about it in a year with the prefix of 20. Every programmer who has ever single-handedly writ
by gary17the 4y ago
This is, IMvHO, such old news that it feels... weird to still read about it in a year with the prefix of 20.
Every programmer who has ever single-handedly written a 100,000+ LOC software system will tell you the same thing: shift as much responsibility on the compiler as you can and have the compiler check the code you write to any extent technologically possible.
Getting rid of bugs by experiencing, diagnosing and fixing them takes at least ten times more effort than getting rid of bugs by not making them in the first place, through expressing the problem at hand with a strong type system.
When you also consider the never ending necessity to introduce change to an already written software system, thus the necessity to refactor code (in the sense of altering the previously assumed meaning of its idioms), the critical advantage of a strong type system becomes self-evident.
(Yes, Rust 4ev3r! ;))
- c54 4y agoI agree with this, yet look at some of the extremely salty comments in this thread. People are upset that something might be useful and that they might benefit from learning it or changing their ways.
- tyingq 4y agoSome of the salt might come from experiences using dynamically typed languages that later had some amount of stronger typing added on. No matter how well that's done, it creates friction somewhere in the process interacting with existing code. That is, I can agree that an inherently strongly typed language has benefits, while also being skeptical about bolted on additions.
- c54 4y agoMakes sense. People have been burned. Probably there are lots of people who think about typescript environment setup and source maps when they think about typing, or who think about python's "isinstance(str, foo)". Or who think that it's overly complicated arcane nonsense with weird terminology (lookin at haskell). Or that types specifically refer to borrow checker woes in rust.
- suzzer99 4y agoIt's weird to me how scanning the comments all seem to refer to systems with 100k-ish LoC and dozens of contributors. A big chunk of my job is writing node microservices in AWS Lambda. I do everything I can to avoid shared library code, since past experience tells me there be lots of dragons (mainly in when and how to push or pull lib updates to components). I have a very tiny shared lib that I try to never touch and definitely never introduce breaking changes. Unit tests are a breeze since I never have to cast objects or worry about generics, etc. Typescript would slow me down so much and add absolutely no benefit. Maybe I'm misinterpreting though and no one is claiming Typescript would benefit here. We also have some C# lamdbas and I find writing unit tests for those so much more of a pain - since the shared libs have generics and I'm always casting things. But admittedly I don't know all the tricks.
- hither_shores 4y ago> since the shared libs have generics and I'm always casting things. This indicates to me that you're trying to write code that isn't correct (not doesn't work, but rather only works because of implicit couplings between components) and/or doing exotic lisp-style metaprogramming. In the latter case, yeah, C#'s type system isn't powerful enough. Others are (to an extent: arbitrary code execution at compile time is never going to be completely safe). In the former case ... that should be difficult. Forcing you to be explicit is half the point of a type system.
- noduerme 4y agoCasting is often necessary for parsing inbound data from certain mysql libraries or CSV or JSON depending on how it's written. I would guess that might be what the parent is talking about. That said, if you don't cast or parseFloat or whatever in JS you're going to have a lot of trouble. And if you're doing that, why not do it in Typescript where you'll know that the data you're accessing has been safely cast based on its type.
- xigoi 4y ago> Casting is often necessary for parsing inbound data from certain mysql libraries or CSV or JSON depending on how it's written. No, that's what sum types are for.
- benreesman 4y agoBased on the author’s examples and the JS-ish looking code in the article, maybe PureScript in general and row types in particular, uh, 4ev3r?
- david422 4y ago> shift as much responsibility on the compiler as you can and have the compiler check the code you write to any extent technologically possible. I think that people first starting out or people who have never worked on large/new code bases with a diverse range of authors don't seem to appreciate this concept.
- kodah 4y agoMy hypothesis is that it's so old to you because that discovery and the spreading revelation was first order to you. To people learning programming today, they end up having to somewhat rewind the timeline and learn everything new at 2x speed. That's to say, having old conversations with new engineers is a really refreshing exercise and I'd encourage the world to continue doing it.
- highwaylights 4y agoI’d take this further. I was listening to the John Carmack episode of Lex Fridman from the summer, and he makes a comment about being frustrated that in the Valley there’s an almost religious opposition to IDEs, debuggers, and static analysis. Some of those tools have only become more powerful over time and I’m perplexed as to the mindset that would make a person averse to automating the drudgiest parts of their job in a career that is almost entirely based around automating things.
- bluGill 4y agoI'm adverse to debuggers as i've more than once caught myself following a rabbit hole of steping through code instead of thinking. IDEs have some use, and static analysis has proven to catch the same mistake over and over, but only as the authors of those tools have discovered that false positives cannot be allowed ever, once there is a false positive the tools is worthless.
- icedchai 4y agoI find debuggers more valuable with dynamically typed languages, especially Python. It's handy to be able to drop a `breakpoint()` in the middle of a script when you have no idea what a function is actually returning. The happens more often than you might think.
- bornfreddy 4y agoOf course, when this happens the bug you are hunting is not your only problem. You really should clean up the code to make it clear what is being returned from the function.
- astrobe_ 4y ago> I'm adverse to debuggers as i've more than once caught myself following a rabbit hole of steping through code instead of thinking. Yes. I was kind of forced to think and do printf debugging at the beginning of my career, after having used before that (as a hobbyist) quite good asm debuggers. Maybe that's just me, but I also was, I believe, a bit over-reliant on the debugger - I would just compile, run, see what happen, and launch the debugger if something didn't work. Nowadays I could use sometimes a debugger - but the system I work with is sort of soft real-time so stopping at a breakpoint of even slight changes in timings can change the context - in some cases even printf debugging could make a bug vanish. If nothing else, debugging without a debugger is a good exercise in logically thinking - and it can save time too.
- emodendroket 4y agoI don’t disagree that it makes things much more pleasant, but I started doing this around 2013, which, while old, was still a year beginning with 20, and consensus was trending the opposite way and people were bullish about stuff like Ruby. The pendulum has really swung in the other direction.
- noobermin 4y agoNo, there really is no new insight OP or anyone else has. At the end of the day, the only thing that matters is writing something that works and works well. Hackers go through too many moodswings to be worth paying attention to when they start telling you how you should code.
- zbentley 4y ago> Hackers go through too many moodswings True! But computer scientists (who are sometimes also hackers, sometimes not) apply research methods to existing codebases and the practice of coding, and have repeatedly presented findings that indicate that, mood swings/fads/hype cycles aside, some techniques really do deliver better software quicker. The VPRI STEPS work is an interesting example of this. That's not to say that every CS methodology paper should be taken as gospel; we have problems just like other disciplines, sometimes more. But it's a far cry from post-hoc rationalization and hacker mood swings.
- emodendroket 4y agoDoesn't really follow that because you ended up with a successful product that means it was the best way you could have possibly done it. I don't feel like I'd learned everything I know today the first time I delivered a successful product, and I doubt I know everything I'll know in the future either.
- waprin 4y agoI noticed this too and I have a simple explanation. Ruby and Python overtook Java and C++ in the early 2010s in _spite_ of their lack of a good typing system, not because of it. On the whole, they are much more productive languages. Now we're seeing languages that have Ruby / Python productivity but also have much better ways of static typing such as Typescript and Swift. And the Ruby / Python community is more open to static types as well. The problems of ~2010 Java and C++ were mistakenly pinned on static types and the framing of "static vs dynamic languages" was always a red herring. Java and C++ were just crappy languages (at least in 2010, not sure about modern incarnations). It really is a shame that Swift is so confined to the iOS world because it's such a great example of how you can have a language that feels like a scripting language but with much more advanced type safety.
- deltasevennine 4y agoBut there's a paradox. Why does 100,000 lines of code of python tend to be safer and more manageable then 100,000 lines of C++ despite the fact that python has no type checker and C++ has a relatively advanced type checker? Why do startups choose a python web stack over a C++ web stack? I don't think it's "self-evident." I think there's something more nuanced going on here. Hear me out. I think type systems are GREAT. I think python type hints and typescripts are the way forward. HOWEVER, the paradox is real. Think about it this way. If you have errors in your program, does it matter that much if those errors are caught during runtime or compile time? An error in compile time is caught sooner rather then later but either way it's caught. YOU are protected regardless. So basically compile time type checking just makes some of the errors get caught earlier which is a slight benefit but not a KEY differentiator. I mean we all run our code and test it anyways despite whether the system is typed or not so the programmer usually finds most of these errors anyways. So what was it that makes python easier to use then C++? Traceability and determinism. Errors are easily reproduced, languages that always display the same symptoms from certain errors and in turn deliver error messages that are clear and are readable. These are really the key factors. C++ on top of non-deterministic segfaults, astonishingly even has compile time messages that can confuse users even further.
- tikhonj 4y agoThere is no "paradox". C++ is dangerous because of memory management and awful semantics (undefined behavior/etc), both of which are orthogonal to static typing. It's a bit like saying that there's a paradox: everyone says that flying is safer than driving, but experimental test pilots die at a much higher rate than school bus drivers!
- deltasevennine 4y agoParadoxes don't exist in reality. It's a figure of speech based on something that was perceived as a paradox. This much is obvious. Much of the fervor around dynamically typed languages in the past was driven largely by the dichotomy between c++ and other dynamically typed languages. Nowadays it's more obvious what the differentiator was. But the point im making here is that type checking is NOT the key differentiator here.
- acchow 4y agoYou say “prefix 20” but there was this weird trend in the early-mid 2000’s where Ruby evangelists really believed that TDD is just as good as static types - even better because you’re forced to test actual business logic! And they even managed to convince masses of programmers that this is true! Glad that’s over.
- idontpost 4y ago
- tialaramex 4y ago> (Yes, Rust 4ev3r! ;)) Rust has a perfectly nice type system by modern standards, but it's nowhere close to showing you just how deep the rabbit hole goes when it comes to avoiding bugs at runtime by having stronger type systems. For example suppose my Rust function takes a slice of clowns (named unimaginatively "clowns") and also a usize integer k. Can we write clowns[k] ? Rust says sure, it will emit a runtime bounds check to confirm that k is inside the bounds of the slice. If there are sixteen clowns, and we ask for k = 20, this Rust code will panic at runtime. But we can do better, if we are willing to pay for it. Dependent Types. In a language with dependent types and enough inference our type inference system will conclude that k can be 20 here, thus clowns must be a slice of at least 21 clowns, but this slice has only sixteen clowns - type error during compilation, either k or clowns are wrong. Now, for cases where bounds checking would be the reasonable thing to do, Dependent Types just result in you writing bounds checks, ie in this case checking k < 16, and so it's possible you will just end up doing more work to result in a program that still just says, at runtime, "Nope, not enough clowns" or whatever like in Rust. The type system will require you to write correct bounds checks, but the Rust bounds checks are auto-generated, so they're correct too. But in cases where bounds checks were not the only sensible approach, or maybe you didn't even realise a bounds check would be emitted because you assumed it was statically correct - this can catch some bugs at compile time which would otherwise survive into a running program, "Shifting left" is I believe the usual phrase to describe this improvement. If you thought the function is obviously correct, "Of course there are more than k clowns" but it isn't, the type error may cause you to take that extra moment to think about it. "Wait, why can there be fewer clowns than... oh, I didn't mean clowns here, this should say circus_performers. I'm not even using the right slice!".
- creata 4y agoI don't know about this. Even some of the people who use dependently typed proof assistants seem to doubt that they should be used much in the programming part (as opposed to the proving part). Also, some of the examples you give might be addressed well enough by Rust's const generics. https://xenaproject.wordpress.com/2020/07/05/division-by-zero-in-type-theory-a-faq/ https://xenaproject.wordpress.com/2020/07/05/division-by-zer... https://www.cs.ox.ac.uk/ralf.hinze/WG2.8/26/slides/xavier.pdf https://www.cs.ox.ac.uk/ralf.hinze/WG2.8/26/slides/xavier.pd...
- drpixie 4y agoWe (the industry) are still so quick to disregard the benefits of strict typing. "Back in the day..." I worked on a collection of vital (to the company) infrastructure apps written in Borland Turbo (object) Pascal. Strong static type checking was enforced by the language. Good type design and strict type checking meant that it was normal that when a program compiled, it was bug free! Much as I enjoy the flexibility of python, I know that every refactor or significant change means that there are now execution paths that have not been exercised - the burden of comprehensive testing is enormous, far outweighing the convenience of dynamic typing.
- kaba0 4y agoWhile I also agree that static typing is the easiest, statically decidable way to significantly increase program correctness, I’m not sure we can do significantly better with it then we currently do. Most interesting properties are not expressible even with dependent types, and those are very hard to prove, making their advantages non-no-brainers. What I’m trying to say is that we should be open about another concept, for example contract-based programs (clojure’s spec for example), because they might have better properties.