←back to thread

517 points bkolobara | 3 comments | | HN request time: 0.548s | source
Show context
BinaryIgor ◴[] No.45042483[source]
Don't most of the benefits just come down to using a statically typed and thus compiled language? Be it Java, Go or C++; TypeScript is trickier, because it compiles to JavaScript and inherits some issues, but it's still fine.

I know that Rust provides some additional compile-time checks because of its stricter type system, but it doesn't come for free - it's harder to learn and arguably to read

replies(17): >>45042692 #>>45043045 #>>45043105 #>>45043148 #>>45043241 #>>45043589 #>>45044559 #>>45045202 #>>45045331 #>>45046496 #>>45047159 #>>45047203 #>>45047415 #>>45048640 #>>45048825 #>>45049254 #>>45050991 #
pornel ◴[] No.45043105[source]
To a large extent yes, but Rust adds more dimensions to the type system: ownership, shared vs exclusive access, thread safety, mutually-exclusive fields (sum types).

Ownership/borrowing clarifies whether function arguments are given only temporarily to view during the call, or whether they're given to the function to keep and use exclusively. This ensures there won't be any surprise action at distance when the data is mutated, because it's always clear who can do that. In large programs, and when using 3rd party libraries, this is incredibly useful. Compare that to that golang, which has types for slices, but the type system has no opinion on whether data can be appended to a slice or not (what happens depends on capacity at runtime), and you can't lend a slice as a temporary read-only view (without hiding it behind an abstraction that isn't a slice type any more).

Thread safety in the type system reliably catches at compile time a class of data race errors that in other languages could be nearly impossible to find and debug, or at very least would require catching at run time under a sanitizer.

replies(4): >>45043414 #>>45043440 #>>45047837 #>>45052706 #
zelphirkalt ◴[] No.45043414[source]
What annoys me about borrowing is, that my default mode of operating is to not mutate things if I can avoid it, and I go to some length in avoiding it, but Rust then forces me to copy or clone, to be able to use things, that I won't mutate anyway, after passing them to another procedure. That creates a lot of mental and syntactical overhead. While in an FP language you are passing values and the assumption is already, that you will not mutate things you pass as arguments and as such there is no need to have extra stuff to do, in order to pass things and later still use them.

Basically, I don't need ownership, if I don't mutate things. It would be nice to have ownership as a concept, in case I do decide to mutate things, but it sucks to have to pay attention to it, when I don't mutate and to carry that around all the time in the code.

replies(5): >>45043496 #>>45043550 #>>45043678 #>>45044243 #>>45050174 #
arnsholt ◴[] No.45043496[source]
Ownership serves another important purpose: it determines when a value is freed.
replies(1): >>45044466 #
1. zelphirkalt ◴[] No.45044466[source]
I guess it is then a necessary complication of the language, as it doesn't have garbage collection, and as such doesn't notice, when values go out of scope of all closures that reference them?
replies(2): >>45045566 #>>45051647 #
2. steveklabnik ◴[] No.45045566[source]
Yes, but it’s more subtle than that. What Rust does is track when the object goes out of scope, and will make sure that any closures that reference it live for a shorter time than that. Sort of backwards of what you’re asking.
3. pclmulqdq ◴[] No.45051647[source]
The borrow checker is a compile-time garbage collector. If you think about it in that sense, you can understand a lot of the ways it restricts you.