upvote
> It’s pretty rare that I run into a bug in production that a type system would have caught.

Wow, how different our experiences are. In Javascript/Typescript land, so so many bugs are null/undefined-related and really should have been caught at type level.

In fact, I'd say (without actually measuring it) that _most_ bugs I've ran into in Typescript are due to someone having bypassed the typing (casting, ts-ignore...), or a type mismatch at IO boundary.

reply
Anecdotally, it is very much different in Elixir land. I occasionally see bugs related to something being unexpectedly `nil` but it's pretty rare IME.

I'd love to evidence what I'm saying with specific numbers since this kind of discussion would benefit from being as objective as possible. Sadly I don't have them. But I still believe what I'm saying and I have a few guesses about some of the causes:

1. Immutable data - so, so many bugs are caused by data mutating out from under you in subtle ways. If you write `x = 1` in your Elixir function, nothing can change the value of `x` except an explicit rebinding. You can then write e.g. `y = f(x)` and know `x` remains unchanged after. Note: this is also true even if the variable is a composite type. `my_struct = blah()` will remain the same in it's entirety no matter what you do with `my_struct`. This is different than in JS where e.g. you can change the contents of an object even if it's declared `const`.

2. Assertive style - the Elixir community favors writing things in an "assertive" fashion [1]. Briefly, this a way of writing code that will fail the moment an assumption is broken rather than letting the issue propagate.

3. Pattern matching (somewhat like destructuring in JS) - Elixir code actually ends up feeling "typed" with pattern matching. E.g. `%Time{} = today = Date.utc_today()` will attempt to bind `today` to the result of `Date.utc_today()` and will raise a `MatchError` when the result, a `%Date{}` struct, fails to be a `%Time{}` struct. Or `[a, b] = [1, 2, 3]` will raise a `MatchError` because `[1, 2, 3]` isn't a list of length exactly 2. You can use pattern matching to write very assertive code quite tersely.

These reasons are all local properties of code. But when all its parts are written in this way, a program as a whole gains a level of correctness that's hard to achieve in a dynamically typed language without them.

Also these reasons aren't exhaustive, but they're top of mind when thinking about this topic.

[1]: https://dashbit.co/blog/writing-assertive-code-with-elixir

reply
Not all dynamically typed systems are equal. Just like not all statically typed systems are equal. Python and Javascript are a mess. But languages like Elixir aren't just Java without types.
reply
javascript is like… unusually messy and weird, so maybe that colours most people's perspective. you don't have to worry about type coercion and weird kinds of equality and so on in python and ruby to anywhere near the same extent.
reply
Go is pretty great - here's a list of tools I use to help me write/build Go- maybe a few of them will also be what you need: https://www.bbkane.com/blog/go-project-notes/
reply
> It’s pretty rare that I run into a bug in production that a type system would have caught.

Well yes, surely because you’re not designing your system around the type system. You need to architect your project to lean heavily on types, pattern matching, etc to actually gain the benefits. If you move a JS project to TS and just rename the files, yeah there’s going to be no difference, you must reengineer the entire codebase to leverage the type system.

Personally, after moving to TS I’ve been completely sold on types and am currently planning to migrate my app to F# so I can gain even more benefit.

reply
C is among the most token efficient languages out there and is statically typed.

Typescript is very verbose thus it cannot compete with much denser languages on token efficiency.

By the way, the biggest reason many love statically typed languages, especially those that are quite expressive like TypeScript is for the domain and data modelling. Makes it easier to reason about the program and to refactor.

reply
I tried doing my side projects in Go and one thing I miss is the rails console which is so helpful. I guess I could have it write a go console or something but it’s not quite the same
reply