Honest question: When would it ever really make sense to use Rust on the server for a service that interacts with a SQL database heavily enough to justify using such a library?
Wouldn't waiting on the network eat up any possible performance gain you could expect from Rust vs something like the JVM or Go runtime? Before modern day JavaScript JITs, relational database systems were the epitome of dynamic runtime systems. There's so much performance variability in the query planner, network, disk caching, etc, to make garbage collection a rounding error. Zero-cost abstractions are just not a particularly useful thing in this context from what I can tell.
Even if you do have genuinely CPU-bound tasks, why wouldn't you use Rust for those modules + call it via FFI from whatever is doing most of the boring business logic? If it's just about static-type-check-all-the-things! I just can't get excited about it vs something like Go.
Short version: Because Rust's type system is a joy to use, and the reason I made Diesel was to try and push it forward in higher level contexts. I'm finding myself more productive in Rust than I am in any other language.
In my limited experience using both Go and Rust for hobbyist web scraping, I haven't found either language to have a significant edge in development difficulty. Go's most salient edge over Rust would be in the more numerous and mature libraries.
So if Rust is not substantially easier or harder than Go, when Rust catches up to Go in the library ecosystem, I can see why people might want to use Rust. Also, it's nice to have better language support for functional strategies.
I think that Rust is substantially harder than Go. At least extrapolating from my personal experience and the 6+ highly-skilled people I've watched learn both Go and Scala simultaneously.
I just started learning Rust and its type system is much simpler than Scala. What makes it powerful is some well-designed somewhat orthogonal features (generics, type traits, the ownership system, algebraic data types, macros).
I didn't pick up Rust as quickly as Go. However, that's not really surprising, because Go is approximately the lowest common dominator of modern statically typed languages minus generics. (In a good and bad way.)
At any rate, I started learning Rust ~2 weeks ago and I am already writing small libraries, programs, etc. for my daily work.
Although that took a bit more time than Go, it's also a much more pleasing language to write in (the lack or sum types or generics in Go is very annoying) and you get more safety guarantees.
> it's also a much more pleasing language to write in (the lack or sum types or generics in Go is very annoying)
Interesting anecdote: Last year, for a course I had to write the assignments in Go. As a Rustacean, I grumbled about the lack of sum types a lot, and made various hacks via interfaces writing unidiomatic Go code to simulate them. My code design was also very Rust-y and unidiomatic.
This year, I'm TAing the same course, and there's a similar assignment. One student's submission was eerily similar to my design (by now I knew that it was unidiomatic), down to the hacks used. It also contained a comment saying "missing Rust's enums" (my code contained a similar comment to explain the hacks). At first I thought it may have been copied from my code (which can be found if you're looking for it), but it was different enough in other areas. I dug a bit and found that the student was indeed a rustacean.
It's rather interesting that two rustaceans used the exact same hacks and same overall design when asked to code in Go.
Surprisingly, I don't miss generics too much in Go. interfaces used to make me cringe due to the extra runtime cost (since I knew Rust before learning Go, and such solutions would make me cringe in Rust), but once I got used to Go I learned to use them properly. Named interfaces are pretty easy to use and let you structure the code decently well, just like proper generics. They may have a runtime cost, but Go doesn't put as much focus on that as Rust.
On the other hand, easy-to-use non-hacky sum types are something I miss from Go all the time.
I think you're right--Rust is harder to learn than Go--but I also think that doesn't really matter, since the important thing is whether people fluent in both languages can write code faster in Rust or Go. I have not seen many if any instances in which people who actually know Rust write code more slowly in Rust than they would in other languages (modulo compiler performance). The borrow check is, like, less than 5% of the errors I see, and the errors are at this point not significantly harder to fix than a misspelled variable name.
> people fluent in both languages can write code faster in Rust or Go
As someone belonging to that group, I agree. short programs are easy to write in Go. If I need to write some utility script I would do it in Go (or more likely python). However, if I need to write a whole new thing I find it very easy to design in Rust in a modular way.
Similarly, if I have a Go and a Rust codebase in front of me, and I need to make changes, it takes longer to work with the Go codebase for nontrivial changes. But this is less stark a difference than the above.
I will say that "modulo compiler perf" is an issue. I was tinkering with the Go compiler and the fact that I could try things out quickly was a big boon. However, I had to spend time figuring out which interface goes where (the documentation doesn't show interfaces implemented on types, you have to figure it out by looking at the source -- this is something that could be fixed though), so it might even out.
But yeah, fixing errors is not hard in Rust (nor do I often get borrow errors, usually it's other stuff), and in fact I find it easier to do than Go because Rust provides extensive errors with suggestions as well as showing the erroring thing inline, whereas Go just points out a file and line number (Again, this could be fixed).
My productivity has been greatly improved by restricting myself to `cargo check` when writing code. It only does type and borrow checking which is much faster than doing all of the LLVM passes (or whatever rustc does after those passes, on that subject I am ignorant).
Note that even for large codebase, the Go compile is faster than Rust up to typecheck. Not much faster, but when I use Go I get errors immediately; whereas in Rust I often context-switch to wait for errors (both for large codebases). Some planned improvements to Rust may fix this.
Fair enough, and being honest I haven't tried Go yet so I have no basis for comparison between the two compilers.
I've found that when using Atom with linter/linter-rust installed and setup with cargo check I rarely context switch while waiting for errors/warnings to be highlighted (and this is on a 1.6Ghz Xeon machine at work). But maybe I'm just OK staring blankly for slightly longer than others :).
Well, I work with really large codebases in Rust (Servo or Rust itself), so the twenty seconds to a compile error are a lot. Whereas when hacking on Go's compiler it's much, much less.
That's valid, but ORMs have been pretty standard for years now too. Most mature languages have either ORMs or some database abstraction libraries, so it's good to see Rust getting those now.
It seems like the intersection of good use case for Rust and need to use SQL, will also intersect with "minimal SQL needs", hence preference for simpler libraries.
If you're talking about query string construction performance, I'm not sure I've ever seen even a Ruby application where query string building was a bottleneck vs the network.
Forgive me, I didn't intend to be so argumentative. I genuinely want to understand. I'm trying to figure out if there are whole categories of use cases that I just don't have any exposure to.
As a side note: I keep trying Rust over and over again, and just can't get in to it. I think my brain just doesn't work that way. For my hobby project that needs super low level perf, I've moved a codebase from C, to Rust, and now to http://terralang.org/ and I'm finally quite satisfied with how the project is going.
Naw, it was my response that was more so than I wanted it to be. No worries. :)
Rust focuses on "zero-cost abstractions", that is, if you had to implement a feature yourself, you couldn't do it any better.
So this library, while more complex than a straightforward binding, has more features that are useful, like increased safety, while also being faster. A win-win. And very much in line with Rust's overall philosophy.
For me Rust compiler and type system is much much better than the one in Go. Rust is still very far from Go right now though but I like the "if it compile, it works" which is not a certainty in Go.
I think it's hard to tell whether a language (by itself, not counting the libraries) will be good for something until you try. Rust has enough going on that some creative people might find some really useful things it can do in surprising spaces.
Think about JavaScript and Node.js. Who would have predicted that?
Even if we were to assume that GC is better than manual memory management for servers (something I think is not really true), this presupposes that the non-memory-management-related parts of Go's type system are better than those of Rust. I disagree with that for many reasons.
In the context of my original post: 1) garbage collection, which isn't a big deal for most server applications and 2) simplicity, where the complexity of Rust only buys me marginal performance of questionable utility for the sorts of use cases where I'd be talking to a SQL database.
But the sorts of use cases where you'd be talking to a SQL database do benefit from generics and ADTs. For example, generics are good to avoid having to write for loops over and over, which is pretty pointless for application code (and, I'd argue, for systems code as well--for loops are just bad). Pattern matching is nice for high-level app logic, which often has the flavor of "if A, do X; if B, do Y; else do Z". Generics enable try!, which is a lot nicer than C-style error handling. And so on.
We're not going to settle the dynamic vs static debate in this thread, so I'll refrain from commenting on safety and productivity :-)
Anyway, I don't mean to dump on your work. It seems like it's actually quite a nice implementation. I'm just questioning 1) the size of the audience and 2) Whether or not the audience who thinks they want this should actually want this.
I like writing Rust for more reasons that CPU efficiency.
In fact, that's behind: strong memory safety, Option/no-null (probably lumps in with "strong memory safety") and of course generics and the type system at large.
The speed is honestly a nice benefit. (I'm not being sassy, I don't have speed intensive applications and still reach for Rust).
Wouldn't waiting on the network eat up any possible performance gain you could expect from Rust vs something like the JVM or Go runtime? Before modern day JavaScript JITs, relational database systems were the epitome of dynamic runtime systems. There's so much performance variability in the query planner, network, disk caching, etc, to make garbage collection a rounding error. Zero-cost abstractions are just not a particularly useful thing in this context from what I can tell.
Even if you do have genuinely CPU-bound tasks, why wouldn't you use Rust for those modules + call it via FFI from whatever is doing most of the boring business logic? If it's just about static-type-check-all-the-things! I just can't get excited about it vs something like Go.