← Back to context

Comment by ggregoire

5 years ago

> The older I get, the more I appreciate dynamic languages.

Exactly the opposite for me. I just can't stand hovering a variable or a parameter and not getting its exact type, or typing "." after a variable and not having my editor gives me all the available methods on that variable, or running my code just to discover that it instantly crashes because I made a typo or forgot an argument or passed the wrong argument or tried to call a method that doesn't exist on that variable or whatever other issues that happens only with dynamic languages. What a waste of my time.

As I said in another ranty response in this thread, I do not understand how people enjoy spending time debugging trivial issues, that even a simple static type system would just plain tell them at compile time.

  • I've been programming for over 20 years too, and I like dynamic languages. I like them a lot more when they're properly tested and well architected, but even the tire fire codebases are at least debuggable. The compiled stuff helps with types catching the trivial bugs, yes, but it's way too complicated to quickly debug things like seg faults. Dynamic languages let you introspect and modify things way more easily, and this makes things like fakes and mocks for testing way easier. It makes debugging easier. And not having to wait an hour for something to compile is nice.

    That said, I love the speed of compiled languages. I once converted a simulation from Python to Cython and saw a 10000x performance boost because of CPU caches and all that. Usually the gains are closer to 10x to 20x, but in some rare moments it's like a rocket ship vs a hang glider.

    • EDIT: Reading again, I think you are comparing interpreted with compiled languages, not so much static with dynamic type systems.

      Seg faults are a prime argument for static typing. The more static and stricter the type system, the less things like seg faults can even happen. Compare Rust to C (both are static, but one more than the other), and at the extreme end handwritten assembly (extremely dynamic). Those are languages used by kernel developers, where errant memory accesses of all kinds are a constant concern.

      I don't know why dynamic languages would make introspecting things easier, or debugging in general. I agree that mocking can be easier with dynamic types. Compilation rarely takes long nowadays (incrementally it's usually just a few seconds), so the time saved in knowing that the code is still correct at least within the confines of the type system is well worth it.

      4 replies →

    • What's a seg fault? I jest, but static languages have come incredibly far since C++ (where they are already less common than in C) and I truly haven't dealt with a segmentation fault in the past many years working with static languages.

      4 replies →

    • > but it's way too complicated to quickly debug things like seg faults

      I know you've listed the common argument for static vs dynamic (dynamic -> so fast to code but slow to run, static -> way too complicated)but after a decade in SE I still have yet to see some good evidence of this.

      Yes some static languages (like Java) will make developing certain things slower vs JS but is Java a good statically typed language ? Maybe these statements are "true" today with the current implementation of one or the other but there are a lot of languages that I just can't see getting in the way.

      A new example of this: Kotlin and Swift are statically typed and I would love love to see where it slows these mythical developers that are so fast in a dynamic language but would be slowed down using them. There's obviously going to be a cost for the actual compile time but that should be minimal.

      Unfortunately I'm starting to believe that this is just another case of certain developers are used to certain languages.

      The trend of the JS move to TS also points to this. Basically JS looks very similar to Kotlin and Swift (TS is basically identical).

      To look at your specifics > Dynamic languages let you introspect and modify things way more easily, and this makes things like fakes and mocks for testing way easier. It makes debugging easier. And not having to wait an hour for something to compile is nice.

      > Dynamic languages let you introspect and modify things way more easily

      In what way ?

      > and this makes things like fakes and mocks for testing way easier

      Fwiw this is what that fake/mocks look like for a static language `val x = mock<User>()`

      To be fair that's using a library and maybe that's part of your criteria ?

      > It makes debugging easier

      ? how, I can see the argument for the other way (one less thing the developer has to worry about - typing issues) but how is dynamic easier to debug ?

      > having to wait an hour for something to compile is nice

      Completely Fair. Now whether or not the thing you're working on would take an hour to compile I highly doubt. If you're working on a project that would hypothetically take an hour to compile then I really hope it's not written in a dynamic language.

      Not trying to pick on you at all, I believe a lot of developers would agree with you but I'm starting to think that there are developers that are just used to one or the other. I have to point out that I could be thinking this way with respect to statically typed languages but I really have a hard time seeing this point (as I would be if I was falling into the same trap I'm "accusing" you of).

      3 replies →

  • I mean by now it should be clear to everyone that there are certain trade-offs in the choice dynamic vs static typing.

    I do like clarity of static type declarations, also the absence of weird polymorphism like functions returning a number or al ist of numbers depending on their parameters, etc.

    But then, many statically typed code bases are just tested abysmally. It is as if the type signatures would constitute proper tests. I realise that you don't need to write as many tests in a statically typed setting, but in many cases - and esp. in underpowered type systems - the types won't test the program's logic.

    • You do need to write less tests with a static language. The types in your program are proof that your program is correct within the confines of the type system (literally, even in the mathematical sense).

      The stronger the type system, the more properties can be proven through it (at the extreme end there are, unfortunately not Turing complete, languages where you can prove every single property--those are more used as theorem solvers however).

      Back to "common" statically typed languages, there is still heaps and loads to test, as you say. Not writing those tests is not really the fault of the language...

      1 reply →

  • I think it depends on what you’re doing. The author of the the Reddit post mentioned he’s primarily working with data systems. I can see the appeal of someone running quick, ephemeral data analysis not wanting to deal with static typing. But for long term use cases the static typing guard rails is definitely nice.

    • > I can see the appeal of someone running quick, ephemeral data analysis not wanting to deal with static typing

      I've seen and heard this, (Data science field definitely loves their Python and numpy) but I really believe the common problem of non-reproducible research is partly due to the language choice (and probably more to the root cause - this sentiment in research).

I think it's a grass-is-always-greener thing?

Early in your career, you lean into one or the other. And then years later, after you're confident you're right, you find yourself trying the opposite paradigm and liking things about it.

Both have pros and cons, and if there was a correct answer we'd all just go with that one!

  • Yeah, this is something I’ve been pondering about. I’ve been doing 10 years of C++, and after a 6 months affair with Haskell fell in love with LISP. Now I’ve been doing Clojure professionally for about 5 years, and now am in a phase where I realize the grass is not green anywhere. I’ve been shocked at some of the bugs in my Clojure code that went unnoticed for way too long, and at the same time I remember the amount of “compiler fighting” that C++ or Haskell required.

    It’s just a trade-off, in the end, and depends on what poison you can digest.

  • I've switched between the two several times – not out of choice, just because that's what was needed. The order was BASIC, C, Python, Java, Go, Python, with Javascript mixed in the for the past few. I mostly prefer dynamic languages because static typing is just redundancy. The point of programming is to express high-level concepts which can't be captured quickly with types - if you don't understand the concept of the arguments and return types, you are missing the contract. Types can be helpful as the beginning of docs, but that's it.

    • Yes, types are redundant, and that is their entire point. Just as much as giving your functions and variables names is redundant, you could just number them. So is splitting up your project into multiple files, all comments, and even structural keywords themselves--you don't need "for" and "while", you just need "goto".

      Take all that redundancy away and what you get is not even assembly, it's exactly machine code. We used to program computers that way when they were invented. We still do sometimes in extreme situations. We got away from it for almost all of programming because it's incredibly error prone (and tedious).

> Exactly the opposite for me.

Yeah, same here. I started my career as a huge dynamic languages fan, and Python was my favourite language for over a decade.

But now, after 20 years, I appreciate a static language with proper IDE support and code completion. Offload the work to the computer, that's what we do for a living after all.

However, after spending a year working in Rust, I think this can be taken too far. The safety guarantees in Rust are amazing, but the overhead for contorting programs to a form the borrow checker will accept, and the mental overhead related to async/await compared to goroutines is too much.

My favourite language is now Go, and I find it strikes a good balance between static checks and productivity. Rust is still a more elegant language in many ways with things like generics and iterators and their enum types (algebraic types I think is the term?) and zero-overhead abstractions and clean error handling. Go feels a little hacky by comparison. But it's simple and way more productive for me personally, so I prefer it.

Interestingly Evan Wallace (constexpr here on HN) implemented esbuild in Rust initially, and switched to Go and stayed with it for much the same reasons, but also noted that the Go version performed better: https://news.ycombinator.com/item?id=22336284

> But at a high-level, Go was much more enjoyable to work with. This is a side project and it has to be fun for me to work on it. The Rust version was actively un-fun for me, both because of all of the workarounds that got in the way and because of the extremely slow compile times.

After a year of working with Rust and switching back to Go, I second this. I'm enjoying programming again and finding it easier to put in long hours.

Agreed. Try going from "I think this is a callback that returns a promise which can return a string or an int?" to "The compiler/IDE are telling me this future can only return an int and won't let me advance until I make my code comply"

Agreed. I did this journey twice. It was all static types when I was in high school and early college. Then I thought I was too smart to need the computer to do all that type checking for me ("I know what my program does, I don't need a compiler's help!") later in college and early in my career. Then I got incredibly sick and tired of working on really big projects in dynamic languages lacking the ergonomics of good static analysis.

I started programming with .Net languages via Visual Studio (which is quite a good IDE), and I disliked dynamic languages exactly for the reasons you list. But nowadays I mostly prefer dynamic, optionally typed languages ala Julia.

Typing a '.' and seeing the members is very nice, except when the type is not concrete and it's not clear what type is actually being returned. Then you'd have to do trial-and-error using a slow compile cycle. In a dynamic language like lisp, you could just `(inspect x)`. In Python, you can just `embed()` and run, e.g., `x.__dict__`.

The IDE telling you about syntax errors and non-existent functions etc is very nice, except when you use macros and meta-programming and now your stupid IDE won't just shut up (I have this problem even with Python in VSCode).

I've been doing TypeScript for 4+ years and been a web developer for 20+ years. And I experience literally zero benefit from TypeScript. Never has it given me anything useful. To me, it's a massive pain in the ass that slows down myself and my team, even if they think it doesn't. They just don't know JavaScript or have shitty quality of code to begin with.

That, and TypeScript generics can get so freaking complex that the code does NOT become simple to read at alllllll. It's a massive waste of time.

Also read: https://medium.com/javascript-scene/the-typescript-tax-132ff...

  • In response to that article: Well, probably the gold-standard for "native JavaScript" tooling is actually provided by TypeScript itself lol. In VSCode it's the TypeScript compiler and language server that's providing the excellent JavaScript autocomplete.

    So I'm in agreeance then? Well, no, and that's why I air quoted "native JavaScript". It's extra good because TypeScript/VSCode is silently utilizing the ".d.ts" files that third party libs ship with in the background! I believe as well, at least at one point, it would auto-fetch existing "@types" packages for libs that don't ship their own.

TypeScript, PHP, and Python have support for typing and the commiserate IDE benefits, and I'd imagine these languages account for a super majority of software written in dynamic languages.

  • Yes, I've started using python again with mypy static typing. I can hardly still call it a "dynamically" typed language if I do that, though.

Especially the typos part. In Ruby and plain JS sometimes you feel you need unit tests even for the dead simple stuff cause there might be a typo in there... and such tests are an awful chore to write and much more efficiently caught by static typing

Depends on how expressive you are being.

There are some problems where you don't want any barriers to getting your idea out of your head.

No rules are best for new exploratory code.

Types and structure are good for existing code.

I wrote Ada years ago when it was newish, and it was hard.

But working on existing Ada code is wonderful.

Yeah, I loved it when I started because I could easily try things out in JavaScript. Eventually I've come to love Typescript because I don't waste time on dumb things anymore.

The ideal for me would be some strong static typing mode for the main code providing all the guarantees you want and some dynamic typing mode for the tests which lets you test everything well.

The main downside for me of the static typing is that it's close to impossible to provide a good testing experience, DSLs, mocks and spy objects kind of require some form of dynamic typing to be usable.

  • That’s exactly what the decade old Java for code and Groovy for tests is. Though it’s not used too often nowadays, mostly because Java is enough for testing for most people.