Hacker News new | ask | show | jobs
by ZenoArrow 3467 days ago
Looking at it as objectively as you can, what advantages does dynamic typing have over static typing?

The only potential candidate I can think of is 'more flexibility'.

However, undefined behaviour is not a desirable trait when designing programs, and languages with static types have ways to provide polymorphic functions without unhandled behaviour (such as pattern matching on function arguments).

Some may argue that dynamic languages are more readable, but there are languages with static types that are both concise and readable (Elm being a good example), so I wouldn't class that as a benefit.

Some may argue that the speed of prototyping a solution is a benefit, but the time saved putting together a prototype is often negated by the time spent debugging as the prototype matures.

So what advantages am I missing? There must be something that makes dynamic languages popular. What reasons are there to use a dynamically-typed language over a statically-typed one?

5 comments

Static types limit the expressivity of your code to what the type system is able to prove. Depending on what you're trying to do, you can spend more time arguing with the type system than getting things done.

This really starts happening with a vengeance when you do increasingly lispy things, like creating dsls that move the language closer to your problem domain by writing programs that write programs.

Consider e.g. the way activerecord introspects the database schema to enrich your model declarations without further work from you.

Now there are ways to get similar effects in statically typed systems, but it's much more work, particularly if the dynamism comes from the execution environment (rather than compilation).

Okay, can you give me one example of a useful macro that you'd write in a dynamically typed language. I'd like to see what challenges there are recreating it in a statically-typed language.

Also, regarding activerecord, it seems you're hinting at the benefits you get from composibility, is that correct?

For me, the benchmark is parsing a heterogenous data structure in JSON. For example, an array of inventory items. We get around this by shoehorning them all into a common structure, but in a dynamic language with a dynamic datastore we can store them and access them in a more native (to the problemspace) manner.
Okay, so what problems do you see in using something like active patterns in F# for either parsing an array or a single value within a JSON structure?

https://docs.microsoft.com/en-us/dotnet/articles/fsharp/lang...

That looks interesting. Is there an analogous Haskell or OCaml feature to F#'s active patterns?

Regardless, I still think it's a moot point. I understand that static typing can be great for catching bugs sooner rather than later. But doing that takes time and work. Basically the thing that all static typing advocates neglect is that sometimes I just don't want to put that time and work in up front.

Most people would agree they'd want to put that work in before shipping their software to millions of people, but most code is only used by a few people a few times. The line between development and production is blurry. Most of the time, I would much rather run code that mostly works _now_ and has tons of bugs than have to put in more work. Even if it's not much more work, it's still not nothing. I own my computer and tell it what to do. But a compiler rejecting my code b/c there _might_ be an edge case that has an error is unacceptable. Which is why I would love static typing if you could simply turn it off. I know of some research in gradual typing, but I've never seen it in any mainstream languages.

>"That looks interesting. Is there an analogous Haskell or OCaml feature to F#'s active patterns?"

Based on a quick web search, the equivalent of F#'s active patterns in Haskell appears to be view patterns...

https://ghc.haskell.org/trac/ghc/wiki/ViewPatterns

...and the closest I found for OCaml was polymorphic variants...

https://realworldocaml.org/v1/en/html/variants.html

>"I know of some research in gradual typing, but I've never seen it in any mainstream languages."

When you say gradual typing, do you mean optional type hinting like you can find in Python 3, or something else?

https://docs.python.org/3/library/typing.html

> but there are languages with static types that are both concise and readable (Elm being a good example)

Elm's to me embodies everything that drove me to Ruby over functional languages: Terseness in what to me is all the wrong places, coupled with too verbose typing.

> So what advantages am I missing?

The ones you have glossed over: More flexibility, and ability to be terse while readable. They matter more to many of us than you might think.

What finally sold me on Ruby was when I as an experiment rewrote a piece of queueing middleware we were using from C to Ruby and added significant number of features while cutting the number of lines to 10% of the original. Maybe I could achieve similar compact code with a statically typed language, but the likely candidates at the time at least were either extremely verbose or languages I considered absolutely unreadable (Haskell being top of my list of offenders - most of these languages have syntax that is clearly designed by people who are inspired by maths, unaware or not caring that this will push away most people).

I would love a "more static" Ruby, but I would not be willing to lose the terseness or expressiveness or readability to gain it. Maybe Crystal will get the balance right over time, though personally I believe you can get a lot more performance out of Ruby too without a lot of the sacrifices Crystal is making (but it will take a lot of work).

>"Elm's to me embodies everything that drove me to Ruby over functional languages: Terseness in what to me is all the wrong places, coupled with too verbose typing."

Elm can use type inference to work out types. The difference between this and dynamic languages is that it does it at compile time so you pay no runtime overhead.

Don't believe me? Take a look for yourself...

https://guide.elm-lang.org/types/

> You're either joking or wildly misinformed.

No, I'm speaking from having read a bunch of Elm code.

> Elm can use type inference to work out types. The difference between this and dynamic languages is that it does it at compile time so you pay no runtime overhead.

I know that. It does not change what I wrote as the outcome is that Elm code still includes more type annotations than I'm willing to deal with.

> "It does not change what I wrote as the outcome is that Elm code still includes more type annotations than I'm willing to deal with."

To get a better idea of how much type information you find unacceptable, do you have any problems with typed.rb code?

https://github.com/antoniogarrote/typed.rb

Yes. There's a reason you practically never find people using those things in real Ruby projects, despite the huge number of such libraries that exist.
I think the real reason might be lack of decent tooling, and developer culture.

Most attempts to add static types to ruby code don't come with complementary tools to give us some of the advantages that would immediately gain developer support. In your editor, for example, code completion based on type annotations would be a huge plus, but I don't know of any tools that give me that in ruby (if they exist, I'm unaware). In most cases, your code will still run regardless, unless you use the separate tool to type-check, and are disciplined about its feedback. It's unlikely that all your team will _always_ run the type checker, and although you can have it configured to run the type checker on every save just like you'd do with tests, it's an inconvenience.

In terms of culture, I'm mainly thinking of Rails here, but I can think of more than a few ruby projects/libraries as well. Ruby is, simply put, a dynamic language. Even if you use typed.rb, you won't get much information about the libraries you'll be using. Code completion is mostly based off comments/documentation and only in some editors, and in many cases might not even be there. I also feel that many ruby developers simply don't like types, and that's the end of the story. I'm convinced that most don't see the advantages. For instance, in teams where we've added Rubocop to simply lint our codebases, I've noticed developers complain about warnings and errors that the linter reports, whenever the developer thinks they know better. I imagine the same happening with type annotations in ruby codebases. It would become a task that you run before committing or before a merge request (like tests, in some teams). When they're confronted with a bunch of errors, they'll go into flight mode: "but i've tested this manually and it works, why is this linter complaining, and why is my type checker complaining as well?". Needless to say, the type checker might have just flagged a _potential_ bug for a use case you might not have manually tested yet.

edit: I think tooling can help shift the developer culture aspect. Better tooling provides a better developer experience and in the end that's all we want. Flow and TypeScript are perfect examples (which I adore).

Ruby is dominated by Rails, but Rails sidesteps the issues of undefined state by 'convention over configuration'.

As for other Ruby projects, static typing would help with performance issues, why developers choose not to add types when hitting performance bottlenecks is not something I fully understand, perhaps it's just seen as normal to rely on C modules to increase performance. That said, Graal/Truffle does seem to offer hope that Ruby performance can be greatly improved.

I understand that there are indeed cases where statically typed languages make a lot of sense. But anecdotally, I use ruby for web apps, and honestly in millions of lines I have written, I have rarely run into issues because the language is dynamically typed. Is it because I am so familiar with this style? I mean it isn't just me, other ruby (and previously perl) developers I've chatted with just don't have issues like I commonly hear described.
> Some may argue that the speed of prototyping a solution is a benefit, but the time saved putting together a prototype is often negated by the time spent debugging as the prototype matures.

Most prototypes fail to gain traction and are discarded well before they mature and maintenance costs start rising.

I'm not sure there's an objective truth in programming language comparison. There's just the right tool for the right job. I love ruby because it's a joy to write, that doesn't mean you can or should use it for everything.