5 ms·
For me, Rust is a return to performance without compromising on high-level abstractions (e.g. iterator methods). Rust is very expressive, but at the same time s
by Xorlev 10y ago
For me, Rust is a return to performance without compromising on high-level abstractions (e.g. iterator methods). Rust is very expressive, but at the same time safe and has your back on performance and keeps you safe. Honestly, I feel safer writing in Rust than I do Java. Even Java has its footguns, especially with mutable state being shared across threads. I can't really comment on C++ as I have never written it professionally.
Rust not being a garbage collected language leaves it free to focus on more important problems as well. Not knocking the difficulty of implementing the borrow checker, but once you have GC in a language you spend forever tuning to fit your users' workloads. Unless you're Go, then you optimize for latency at the cost of CPU, but that seems like a very acceptable tradeoff to make given how Go is most commonly used.
I've never seen a single language with so much promise for both systems programming and service/application development.
Edit: Forgot to mention, every time I tried to get into C++, I was always reminded how good I have dependency management in Java. Rust is even better than Java in that realm; Cargo is an amazing piece of software. In that context I like Rust for the same reason I like Go: opinionated tooling. I might not always agree with the decisions, but at least it's opinionated and easy to work with.
- vbezhenar 10y agoNot everyone have to tune GC. I never had to do that. I work with government project which serves the whole country now (small cluster with jboss servers), nobody tuned GC there, because there was no need (except -Xmx setting, of course). I wrote few simple programs with Rust, but its memory management model is much harder to use, than GC (no thinking about memory at all, just don't leak) or ARC (just think about cycles). While I understand why it's necessary to achieve higher performance, it's harder to use for developer. It might have uses for multithreading, but, honestly, I never had any problems with it. It's usually better to write single-thread code and avoid multithreading except in few carefully written places. So it solves a problem I never had. That's my perspective, I mostly did enterprise web development and iOS development. Probably from systems programming things look different.
- steveklabnik 10y agoRusts guarantees aren't just about multithreading: http://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/ http://manishearth.github.io/blog/2015/05/17/the-problem-wit...
- Xorlev 10y agoI can see where my statement was ambiguous, I'd intended to say that the GC developers spend tons of time tuning their implementations to fit their users' workloads. I will say that "government project which serves the whole country now" doesn't really specify how many requests you're doing or what kind of pauses are acceptable. If it's a traditional website, a 300ms GC pause might be invisible. A 2s pause might even be invisible. For a service doing 30,000 requests/s (~1-2k/s per machine), a single STW pause of 2s is _very_ disruptive. Even 300ms is high. A 300ms pause is 600 queued requests @ 2k/s. We certainly tune this service to eliminate most STW GC. We were even hit by http://www.evanjones.ca/jvm-mmap-pause.html http://www.evanjones.ca/jvm-mmap-pause.html .
- Manishearth 10y ago> It's usually better to write single-thread code and avoid multithreading except in few carefully written places. implies that you did have some problem with multithreaded code, which is why you ultimately chose to avoid it. Stuff like rayon in Rust lets you sprinkle multithreading over your codebase very easily without needing to worry at all, because Rust keeps it safe. > but its memory management model is much harder to use IME it takes some getting used to but once you do it's pretty automatic and you don't have to think about it much. YMMV.
- idobai 10y agoIf you're into safety than you should probably go with a functional programming language with low-cost abstractions. Rust isn't an expressive language, its only benefit compared to other general purpose languages is its memory management.
- mmstick 10y agoRust is very expressive. The main benefits of functional programming languages is contained with Rust's Iterator trait and the ad-hoc polymorphism that traits allow.
- kibwen 10y agoI don't know that traits in Rust are an example of ad-hoc polymorphism, since they're fully type-safe.
- burntsushi 10y agoI don't think that means it isn't ad hoc. Type classes in Haskell were originally introduced as a form of ad hoc polymorphism, for example: http://202.3.77.10/users/karkare/courses/2010/cs653/Papers/ad-hoc-polymorphism.pdf http://202.3.77.10/users/karkare/courses/2010/cs653/Papers/a... (One of Wadler's great papers btw, worth a read.) See also: https://en.wikipedia.org/wiki/Type_class https://en.wikipedia.org/wiki/Type_class Of course, Haskell type classes and Rust traits aren't the same. But they are quite similar!
- dllthomas 10y agoAs I understand the term, "ad-hoc polymorphism" refers to dispatch based on types (as opposed to "parametric polymorphism", where one code path works for any type). Nothing to do with type-safety.
- mmstick 10y agoHere's an example: `Stdin` and `File` both implement the `Read` trait. Therefore, you can write a function that takes the traits that you want to use as input parameters. fn do_something_with<S: Read>(source: S) { // do something with input source } Then you can do the following: let stdout = io::stdout(); do_something_with(stdout.lock()); let file = File::open(path).unwrap(); do_something_with(file); You're free to narrow down/expand the types/methods that can be used with the function if you add more traits.
- barrkel 10y agoIf you're in a stateless server environment, GC almost never needs tuning. Stateless servers are close to ideal for a generational GC. Cacheing can muck things up, but if you implement that at a higher level, you're in a good place.
- Xorlev 10y agoThat's fair, so long as all of your requests have similar allocation profiles. I work on a service which has requests of variable complexity ranging from basically free (10s of KBs) to 10s-100s of MB of allocation. G1GC with a low pause target eliminated a lot of the tuning necessary I'll admit. This could also be a "grass is greener" mentality, but I do believe that in return for the upfront development effort of managing memory as you go vs. deferring to GC leads to more predictable results. Of course, if your algorithms suck, nothing will save you. :P
- Thaxll 10y agoAnd when you start managing memory you will discover that GC are more powerful than you thought because your simple memory allocator cannot beat 20+years of engineering in the JVM.
- mmstick 10y agoRust's allocation strategy beats the JVM hands down in every benchmark. 20+ years of engineering cannot cover the flaws of VM and GC languages. Writing efficient stack-allocated software will always trump GC/VM solutions.
- zzzcpan 10y agoNo, nothing can beat manual memory management in performance. GCs don't have a clue where and when they should make what trade offs, but programmers do.
- kibwen 10y agoGC can surpass the performance of manual memory management in certain situations, assuming that the manually managed code is forced to allocate for some reason. GCs almost universally use far more memory than manual schemes, though (I'm having a hard time imagining a counterexample).
- hsivonen 10y ago> Honestly, I feel safer writing in Rust than I do Java. Even Java has its footguns, especially with mutable state being shared across threads. Apart from big differences between Java and Rust like memory management (not just GC vs. lifetimes but also stack allocation), approach to threading, and Cargo vs. Maven, Rust is so much nicer in the seemingly little things like: * UTF-8 everywhere instead of UTF-16 everywhere. * Unsigned integers. * Bytes from I/O being unsigned by convention. * Ability to bake plain old data into the data segment of the executable with genuinely no run-time initialization.
- stcredzero 10y agoUnless you're Go, then you optimize for latency at the cost of CPU, but that seems like a very acceptable tradeoff to make given how Go is most commonly used. Here's how I see the use of GC in Go: It allows the programmer to more easily get to the point where there's a correct, running version of the system. Once you're at that point, you then optimize as much as you need to reduce GC pressure. Emphasizing latency at the cost of throughput is exactly the right tradeoff for this purpose. First you get it running, then you get it correct, then you make it fast. Large pauses are more likely to be a barrier to program development than being a bit too slow.