Part of the reason was Rust's desire to show itself as a direct competitor w.r.t performance, I think.
Say you use a vector in C++. You push one element and pop two. In Rust that's a None. In C++ the answer is UB (in my case 43).
That prioritisation applies to the whole ISO language, not only to the standard library.
What I'm talking about is that Rust's Option is very cheap in all the cases where it can be very cheap, which makes this whole design feature more affordable. C++ eventually grew std::optional which is not powerful enough for this work and yet is also bigger and slower. They could have done better, but safety wasn't a priority.
Unlike C, which the only way to be safe is not to touch it at all.
As for performance, ISO doesn't implement compilers, there are many ways to improve performance while keeping the semantics in line with the standard.
If the compiler vendors decide to focus elsewhere is another matter, a bit like there are languages as complex as Rust and compile faster, because that has been a concern, whereas rustc developers have their concerns elsewhere.
Even your dynamic example won't tell me calling pop/push x/y times respectively will fail if x > y.
I have to trigger it somehow.
I haven't written the Language of Kings in a while: does GCC -Wall truly enable all warnings yet?
clang has a -Weverything and it isn't supported.
The argument is that Rust forces you and in C++ you can forget/the compiler can do what it wants
It's like Yaml parsers, they had "load_yaml" which is unsafe and "safe_load_yaml" which is the secure option. Imagine no surprise when Rubyists went for shorter safe looking method and got their servers pwned.
Depends what you mean by explicit.
Look at it like this:
pub fn main() {
let mut vec : Vec<i32> = vec![];
let x = vec.pop();
println!("{:?}",x); // prints: None
}
In this case you see the value is missing. vec.pop().expect("I want a value")
will panic with "I want a value" because value is empty. And most rigorous way to deal with it is: if let Some(x) = vec.pop() {
println!("{:?}",x);
} else {
println!("EMPTY"); // prints: Empty
}
will either print value or EMPTY depending on what the vector contains.Types like Result will issue warning that you didn't handle the cases.
I looked at your example and played a bit with it and yes I agree with you - compiler does help in this case.
My old text:
So instead of checking if vector is not empty you check that the return result is not empty. I do not see much difference. If Rust compiler would choke when "else" clause in your example is not present I would understand your point about compiler preventing improper access.
> If Rust compiler would choke when "else" clause in your example is not present
The compiler won't choke, but it will stop you from accessing the value.
It doesn't matter if you omit the `else` clause or not, the type system ensures that you can't access invalid values.
Here's a bit of an example based off of @Ygg2's code: https://play.rust-lang.org/?version=stable&mode=debug&editio...
Hacker News will try and discourage really quick back and forth comments. To do so, the reply button is hidden. However, if you click on the timestamp, to go to the comment's own page, you can reply there.
Rust does that with the combination of "sum types" (aka "enums with data") and pattern matching. An `Option<T>` is either `Some(T)` or `None`. Matching on an option with the pattern `Some(value)` creates a new syntactic scope where the value is accessible. This scope is only entered if the `Option` is actually non-empty.
All ways of getting the value from the option are ultimately shorthand for a match in that way. For example, option.unwrap() will either get the value if it there, or panic. Option.unwrap_or(x) will either get the value of it there, or use x instead.
In practice this is x100 less error prone than C++. Source: was burned by vector.front() on empty vectors more than once. In C++, UB. In rust, usually the "empty case" is considered when first writing the code, or at least caught during review (unwraps tend to be very visible in reviews)
I'm not a C++ expert but here is my understanding. Vector is essentially a tuple of (dynamic_array_address: ptr, size: size_t, capacity: size_t). To pop a value from vector you just decrements size. So what happens when you have empty vec? Your size is 0, and you're substracing 1, which causes undefined behavior.
Correct way is to check BEFORE you pop_back().
In Rust, any number of invocation of pop() will not result in undefined behavior. You can ignore the value, or you can check it, but it doesn't expose you to UB just for slightly misusing a vector.
Absolutely and this is exactly what I do. I always check the containers before removing elements.
>"In Rust, any number of invocation of pop() will not result in undefined behavior. You can ignore the value, or you can check it, but it doesn't expose you to UB just for slightly misusing a vector."
I do not understand "slightly misusing" part. I assume in Rust it would bomb if pop() returns "none" and you try for example add said "none" to some number.
That's the thing. It wouldn't. Worse you can do is make whole program panic, with well defined stack trace and message.
It will never return non-sense and pretend all is ok.
https://godbolt.org/z/vYcMhE9h7
> Error: attempt to access an element in an empty container.
It is also what attracted me into C++ coming from Turbo Pascal and Turbo Basic, back in the early 1990's.
Although C++ culture could be much better towards safety, it is definitely better than whatever WG14 is doing, or C has brought into the picture for the last 50 years.
Also anyone that just copy pastes C like code into C++, is the kind of developer that will be using unsafe{} all over the place, on the languages that have them.
C developers like telling themselves that only people with bounded rationality make security critical mistakes. All the skilled C developers have ascended beyond the mortal realm and would never let themselves be chained up with crutches for the weak like affine types or overflow/bounds checking.
Yes you could. But I do not think " cultural" is the right term for not putting all your code in an `unsafe` block
It's not. It's a safety phenomenon. See Java, C# etc.
Java doesn't have huge focus on it, but managed to get it right.
As for your dynamic arguments request, have fun,
In a runtime example I can run it with tests and it would behave fine if both values are same or first arg is bigger, in Rust's case it would behave valid for ANY combination of arguments.
Coming from Java the C++ stuff is jarringly unsafe.
Still, if you want to contribute to OpenJDK internals, they will only be taking pull requests in C++, not Rust.
So better learn how to build those seatbelts and airbags, for all the projects we rely on, including Rust's own reference implementation, that aren't going to rewrite their code from C++ into something else.
> It's easier to work with than C++, but that's fairly faint praise.
So, while Rust positions itself as a C++ alternative with all the complexities that C++ developers love, it may become less attractive for other use cases. For instance, I find it highly questionable to develop a web app in Rust...
Rust as a C++ replacement serves a real unmet need in the marketplace.
Knowing what we know now, we should’ve gone with TypeScript and just written our own Odata filter on top of it, but live and learn.
If I was in a position where I could pick and chose languages, and not worry about how not having TypeScript in most things will mean our best front-end developer can never go on vacation because he’s sort of our only front-end developer, I wouldn’t mind using Rust for web-backends.
Rust GUI is obviously not a great experience. At least not yet. But it’s not that bad either. I think it’s mostly the case of how JavaScript is just so good at it and seeing such a fast pace of improvements because the entire world uses it for most GUIs these days, that it’s just hard for anything else to compete. I mean, look at stuff like Flutter or Blazor, they are backed by Microsoft and Google and they’re vastly inferior choices for most use cases compared to simply building things in React, ReactNative or even electron, and that’s not because I have some wild love for JavaScript, it’s because it’s seeing rapid improvements they dwarf it’s competition simply by being used by a lot of people.
I wish Rust would have someone like Facebook pick it up and build a frontend framework for it, but I think that is just too unlikely for you to bet on, and you certainly wouldn’t want to do it yourself, even as open source because then that would probably be your entire job.
On the flip-side, the packages that handle basic back-end web stuff for Enterprise use are rock solid in Rust. Which is impressive, at least to me, considering it’s young age. I have no idea why, but maybe some serious players are contributing to it because they use it themselves. There isn’t a “Django” or Ruby+Rails for Rust, but if what you’re building is a lot of smaller APIs with various transport methods and data access in an federated authentication scenario then Rust is surprisingly mature for the web. It’s primary disadvantage being that your TypeScript and Rust developers won’t be able to cover for each other (which is why we didn’t poc with Java).
We have yew, and my personal favourite: leptos (https://leptos.dev/)
I mean who'd want to and why bother trying to support that use case? Basically none of Rust's value proposition exists for a web app while nearly every single one of the downsides do.
The single biggest problem I've run into is that there's no real good story for a web app framework (especially since everyone's gone crazy over async). Rocket is perhaps a bit too magical for rust folks and it's been abandoned, but I rather liked it. I've warmed up to axum, but all this async stuff still rubs me the wrong way.
And, yes, compile times still suck.
The number one syntactical beef I've is operators. e.g. == vs ===, ""+number.
any of which offer everything you've outlined
They don't, that's the "problem". Off the top of my head dependency management in Go is not best in class to put it charitably. .NET will tie you more closely to Windows. Sure, mono is a thing but you'll have more packages to choose from and fewer compatibility issues running .NET on Windows.Mono is mostly only relevant if you need platform specific capabilities that wont be covered in .NET.
I'm talking about things like exhaustive "switches", built-in, ENFORCED handling of "missing" values (null, undefined), and finally useful error handling.
I actually don't need any of the baremetal features of Rust. It's just that most of it's "zero-cost" abstractions are still far superior to those of other languages.
(Some dislike it, but Java’s checked exceptions are exact homologous of result types)
Outside of that, yeah they just differ in very low-level aspects that most developers don't even know about.
Do crates have namespaces that ownership is verified for?
I am constantly baffled that NPM, PyPi, crates.io etc. didn't copy this idea for those last two reasons. In my mind, it's not quite best in class without it.
[0]: https://central.sonatype.org/publish/requirements/coordinate...
[1]: https://central.sonatype.org/faq/how-to-set-txt-record/
[2]: https://central.sonatype.org/publish/requirements/coordinate...
[3]: https://internals.rust-lang.org/t/pre-rfc-formal-squatting-p...
[4]: https://blog.sonatype.com/this-week-in-malware-may-13th-edit...
cough C#. You also get LINQ. And a fairly heavy amount of web frameworks in ASP.NET / Razor.
The pieces and features i wanted exist but tying them together was not always straight forward.
From the top of my head I used:
- actix-web
- tracing (logging)
- sea-orm
- config from yaml files and a custom implementation to allow profiles.
- utoipa (for openapi and swagger ui)
- thiserror
In a professional context I would not have used Rust for this project, but it was quite fun to explore it's possibilities and rich crate ecosystem.
I write my web apps in C++. They tend to be little bit more than just query database / update database. They're exposed as JSON based RPC and can be accessed by JS front end from browser or third party systems we interact with. The performance is stellar and the code size is not much different comparatively to using PHP / Ruby / Python / your_pet_goes_here.
But we already have plenty of options for this use case (.NET, JVM, Go, Python, Ruby, node.js, PHP, Erlang, etc. etc.). Very mature ecosystems that solve a lot of different edge cases.
There are very few C++ alternatives worth mentioning, none as mature as Rust in terms of adoption/tooling.
If you need to write a webapp that would require C/C++ kind of memory handling/performance then Rust would be the ideal candidate I think.
I don't know what kind of tradeoff matrix makes you use the Rust graydon describes over the existing options.
For example my main issue with D (but TBH that's something I've given up on actively tracking 10 years ago probably) is that by including GC in the runtime/stdlib - it basically painted itself as a poorly supported competitor to C# rather than a C++ replacement.
Indeed in software engineering there is no silver bullet nor a perfect language for everybody :-)