Rust has the (imo unrealistic) goal of trying to fit an incredibly broad range of use-cases, from embedded microcontrollers to command-line tools to web frameworks, each of which has a different level of abstraction and concerns that are important. When you go up the ladder of abstraction like in this project, stack vs heap, ownership, et al get in the way of dealing with application logic.
I agree it’s stretching for a wide swath of cases, and it will be interesting to see how much of that space it ends up becoming popular for, but I’m not sure I’d call it “unrealistic”. Part of the problem right now - especially in the web space - isn’t the language but a lack of time investment in the ecosystem. Rocket is the most promising web framework Rust has, and its current release has been in RC for 6 months (!). I really hope it gets corporate backing at some point.
That's true, but since the base language is so low-level there are certain things you can't get away from.
You can never get away from the fact that String/&str and Vec/&[] are different. If I'm writing code where every allocation counts, then I need a language to be able to, for example, give me a substring without allocating. If I'm writing web code, though, the number of allocations is probably in the thousands or tens of thousands and I just don't care. But using Rust, I have to care about the difference between allocated types and slices, which is unnecessary complexity.
You can never get away from the fact that heap allocations are explicit, so most kinds of dynamism, since they rely on runtime polymorphism, need to go through Boxes or generic types or something else. I can't count the number of time's I've needed to Box something because I needed runtime polymorphism, or needed to rework an interface because I had Boxed something but now it's not object-safe.
You can never get away from Rust's ownership model, which wreaks havoc on graph-like structures that are common in a domain model (which you'll undoubtedly have in your web app/api. It's no big deal for a language with a GC, but because the memory semantics are difficult, Rust forces that difficulty onto you. Again, it would make sense if I only had some tiny amount of RAM to work with on a microcontroller, but I can spare gigs of server RAM.
All of these (and others, these are just examples) add up to complexity that is unnecessary and overwhelming for the level of abstraction that web projects deal with. Rust certainly has many great things, but it's a trade off, and imo it's one that's not worth it.
Personally, I think tools are better when they target a specific audience with specific goals and specific use-cases. I suppose I stretched calling it "unrealistic" for Rust, since, well, look where it is; I guess it's more just a position I don't understand or agree with.
Honestly the best part of Rust is (most of) the community. Most of the people I interact with are incredibly friendly, welcoming, and interested in making the community better. I wish Swift had half the community Rust does, and wasn't so Apple-controlled, because it feels like an applications-friendly version of Rust.
Rust is definitely not yet as ergonomic as something like Node for writing web servers. Even if Rocket were 100% production-ready, I probably wouldn't recommend it over a GCd language in my own organization unless we needed a) crazy performance or b) crazy type-safety.
But could Rust get there one day?
> I suppose I stretched calling it "unrealistic" for Rust, since, well, look where it is; I guess it's more just a position I don't understand or agree with
I would call Rust's attempted breadth ambitious. I think it's charting new territory and I'm very curious to see how far it will be able to stretch. I don't know the outcome here; nobody does. It's very possible it will never take off for mainstream web dev and will be confined to systems, tooling, etc. But I think there's potential, and I think it's too early to call.
Rust, as a language, isn't a good choice for simple web applications. It's compiler-checked manual memory management. Most of the time I spent with Rust was just getting boggled down in arcane syntax that would probably take me months to become familiar with.
In contrast, Node.js with garbage collection is blazingly fast for web applications.
Rust, though, introduces some really good concepts that I'd like to see in other languages. Matching and error handling takes some time to get used to, but it's much more advanced than exceptions. (Specifically, the caller, not the callee, decides which errors are exceptional and which errors it can pass up the stack.)
Post::find_by_id(id).one(db).await.unwrap().unwrap().into();
I assume this project uses idiomatic Rust code. Is `unwrap().unwrap()` really necessary?Things like this really make Rust unappealing to me.
In practice most people would say that you should avoid using unwrap unless there is absolutely no other way, and in this example you could definitely avoid using unwrap. The code would be a wee bit more verbose but it would be more readable (to me, anyway) and it would avoid a potential crash.
edit to clarify: In Rust, "nulls" and "errors" are part of the type system as structs, with "Option" for nullable types and "Result" for fallible types. "unwrap" is a function that you use if you "know" that the result is 100% not null or an error. Because if you call unwrap on a result that is null or an error, it causes a hard crash. So the only time you use unwrap is if you know you have a situation where a null or an error is unrecoverable and your program should just give up.
This is definitely not one of those cases, which is why unwrap is not idiomatic here. It's the equivalent in Java of an uncaught RuntimeException or an uncaught NPE. And it's setting up newbies for failure when they see this and think that it's The Way™.
match x {
Ok(v) => ..., // doing something with the value v
Err(e) => ..., // handling the error e
}`(i64,)` is a tuple with a single component, the trailing comma disambiguates it from plain parentheses. I haven't needed one of those so far.