Comment by josephg

6 months ago

One big source of bugs in TS is structural sharing. Like, imagine you have some complex object that needs to be accessed from multiple places. The obvious, high performance way to share that object is to just pass around references wherever you need them. But this is dangerous. It’s easy to later forget that the object is shared, and mutate it in one place without considering the implications for other parts of your code.

I’ve made this mistake in TS more times than I’d like to admit. It gives rise to some bugs that are very tricky to track down. The obvious ways to avoid this bug are by making everything deeply immutable. Or by cloning instead of sharing. Both of these options aren’t well supported by the language. And they can both be very expensive from a performance pov. I don’t want to pay that cost when it’s not necessary.

Typescript is pretty good. But it’s very normal for a TS program to type check but still contain bugs. In my experience, far fewer bugs slip past the rust compiler.

Appreciate it, that makes a lot of sense. I feel like I've been trained to favor immutability so much in every language that I sometimes forget about these things.

  • Yes, immutability is great for safety. But the copies you have to make to keep everything immutable extracts a price in copies and garbage collection.

    Rust is advertised as having fearless concurrency. That's true, but not that important as concurrency is not that common. What's important to everyday programming is Rust provides fearless mutability. The fearless concurrency you get with that is just a bonus.

    Fearless mutability provides Rust the same safety as a functional language in a without the speed or space cost. IMO, it's Rust's true secret sauce.

    • Yea this seems like a super power I thought only functional languages had. I have to make time to learn some Rust

  • Similar. I mostly design my code around something like pipe and lifetime. The longer something needs to live the closer it is to the start of the program. If I need to mutate it, I take care that the actual mutation happens in one place, so I can differentiate between read and write access. For anything else, I clone and I update. It may not be efficient and you need to track memory usage, but logic is way far simple.