Matt Godbolt sold me on Rust by showing me C++

238 LorenDB 174 5/6/2025, 5:51:03 PM collabora.com ↗

Comments (174)

dvratil · 3h ago
The one thing that sold me on Rust (going from C++) was that there is a single way errors are propagated: the Result type. No need to bother with exceptions, functions returning bool, functions returning 0 on success, functions returning 0 on error, functions returning -1 on error, functions returning negative errno on error, functions taking optional pointer to bool to indicate error (optionally), functions taking reference to std::error_code to set an error (and having an overload with the same name that throws an exception on error if you forget to pass the std::error_code)...I understand there's 30 years of history, but it still is annoying, that even the standard library is not consistent (or striving for consistency).

Then you top it on with `?` shortcut and the functional interface of Result and suddenly error handling becomes fun and easy to deal with, rather than just "return false" with a "TODO: figure out error handling".

jeroenhd · 3h ago
The result type does make for some great API design, but SerenityOS shows that this same paradigm also works fine in C++. That includes something similar to the ? operator, though it's closer to a raw function call.

SerenityOS is the first functional OS (as in "boots on actual hardware and has a GUI") I've seen that dares question the 1970s int main() using modern C++ constructs instead, and the API is simply a lot better.

I can imagine someone writing a better standard library for C++ that works a whole lot like Rust's standard library does. Begone with the archaic integer types, make use of the power your language offers!

If we're comparing C++ and Rust, I think the ease of use of enum classes/structs is probably a bigger difference. You can get pretty close, but Rust avoids a lot of boilerplate that makes them quite usable, especially when combined with the match keyword.

I think c++, the language, is ready for the modern world. However, c++, the community, seems to be struck at least 20 years in the past.

jchw · 2h ago
Google has been doing a very similar, but definitely somewhat uglier, thing with StatusOr<...> and Status (as seen in absl and protobuf) for quite some time.

A long time ago, there was talk about a similar concept for C++ based on exception objects in a more "standard" way that could feasibly be added to the standard library, the expected<T> class. And... in C++23, std::expected does exist[1], and you don't need to use exception objects or anything awkward like that, it can work with arbitrary error types just like Result. Unfortunately, it's so horrifically late to the party that I'm not sure if C++23 will make it to critical adoption quickly enough for any major C++ library to actually adopt it, unless C++ has another massive resurgence like it did after C++11. That said, if you're writing C++ code and you want a "standard" mechanism like the Result type, it's probably the closest thing there will ever be.

[1]: https://en.cppreference.com/w/cpp/utility/expected

a_t48 · 1h ago
There’s a few backports around, not quite the same as having first class support, though.
Rucadi · 10m ago
I created a library "cpp-match" that tries to bring the "?" operator into C++, however it uses a gnu-specific feature (https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html), I did support msvc falling-back to using exceptions for the short-circuit mechanism.

However it seems like C++ wants to only provide this kind of pattern via monadic operations.

d_tr · 1h ago
C++ carries so much on its back and this makes its evolution over the past decade even more impressive.
zozbot234 · 3h ago
> The one thing that sold me on Rust (going from C++) was that there is a single way errors are propagated: the Result type. No need to bother with exceptions

This isn't really true since Rust has panics. It would be nice to have out-of-the-box support for a "no panics" subset of Rust, which would also make it easier to properly support linear (no auto-drop) types.

kelnos · 2h ago
I wish more people (and crate authors) would treat panic!() as it really should be treated: only for absolutely unrecoverable errors that indicate that some sort of state is corrupted and that continuing wouldn't be safe from a data- or program-integrity perspective.

Even then, though, I do see a need to catch panics in some situations: if I'm writing some sort of API or web service, and there's some inconsistency in a particular request (even if it's because of a bug I've written), I probably really would prefer only that request to abort, not for the entire process to be torn down, terminating any other in-flight requests that might be just fine.

But otherwise, you really should just not be catching panics at all.

tcfhgj · 2h ago
would you consider panics acceptable when you think it cannot panic in practice? e.g. unwraping/expecting a value for a key in a map when you inserted that value before and know it hasn't been removed?

you could have a panic though, if you wrongly make assumptions

conradludgate · 1h ago
Not the same person, but I first try and figure out an API that allows me to not panic in the first place.

Panics are a runtime memory safe way to encode an invariant, but I will generally prefer a compile time invariant if possible and not too cumbersome.

However, yes I will panic if I'm not already using unsafe and I can clearly prove the invariant I'm working with.

pdimitar · 1h ago
I don't speak for anyone else but I'm not using `unwrap` and `expect`. I understand the scenario you outlined but I've accepted it as a compromise and will `match` on a map's fetching function and will have an `Err` branch.

I will fight against program aborts as hard as I possibly can. I don't mind boilerplate to be the price paid and will provide detailed error messages even in such obscure error branches.

Again, speaking only for myself. My philosophy is: the program is no good for me dead.

von_lohengramm · 1h ago
> the program is no good for me dead

That may be true, but the program may actually be bad for you if it does something unexpected due to an unforeseen state.

pdimitar · 1h ago
Agreed, that's why I don't catch panics either -- if we get to that point I'm viewing the program as corrupted. I'm simply saying that I do my utmost to never use potentially panicking Rust API and prefer to add boilerplate for `Err` branching.
codedokode · 2h ago
It's pretty difficult to have no panics, because many functions allocate memory and what are they supposed to do when there is no memory left? Also many functions use addition and what is one supposed to do in case of overflow?
Arnavion · 1h ago
>many functions allocate memory and what are they supposed to do when there is no memory left?

Return an AllocationError. Rust unfortunately picked the wrong default here for the sake of convenience, along with the default of assuming a global allocator. It's now trying to add in explicit allocators and allocation failure handling (A:Alloc type param) at the cost of splitting the ecosystem (all third-party code, including parts of libstd itself like std::io::Read::read_to_end, only work with A=GlobalAlloc).

Zig for example does it right by having explicit allocators from the start, plus good support for having the allocator outside the type (ArrayList vs ArrayListUnmanaged) so that multiple values within a composite type can all use the same allocator.

>Also many functions use addition and what is one supposed to do in case of overflow?

Return an error ( https://doc.rust-lang.org/stable/std/primitive.i64.html#meth... ) or a signal that overflow occurred ( https://doc.rust-lang.org/stable/std/primitive.i64.html#meth... ). Or use wrapping addition ( https://doc.rust-lang.org/stable/std/primitive.i64.html#meth... ) if that was intended.

Note that for the checked case, it is possible to have a newtype wrapper that impls std::ops::Add etc, so that you can continue using the compact `+` etc instead of the cumbersome `.checked_add(...)` etc. For the wrapping case libstd already has such a newtype: std::num::Wrapping.

Also, there is a clippy lint for disallowing `+` etc ( https://rust-lang.github.io/rust-clippy/master/index.html#ar... ), though I assume only the most masochistic people enable it. I actually tried to enable it once for some parsing code where I wanted to enforced checked arithmetic, but it pointlessly triggered on my Checked wrapper (as described in the previous paragraph) so I ended up disabling it.

smj-edison · 1h ago
> Rust unfortunately picked the wrong default here

I partially disagree with this. Using Zig style allocators doesn't really fit with Rust ergonomics, as it would require pretty extensive lifetime annotations. With no_std, you absolutely can roll your own allocation styles, at the price of more manual lifetime annotations.

I do hope though that some library comes along that allows for Zig style collections, with the associated lifetimes... (It's been a bit painful rolling my own local allocator for audio processing).

Arnavion · 28m ago
Explicit allocators do work with Rust, as evidenced by them already working for libstd's types, as I said. The mistake was to not have them from day one which has caused most code to assume GlobalAlloc.

As long as the type is generic on the allocator, the lifetimes of the allocator don't appear in the type. So eg if your allocator is using a stack array in main then your allocator happens to be backed by `&'a [MaybeUninit<u8>]`, but things like Vec<T, A> instantiated with A = YourAllocator<'a> don't need to be concerned with 'a themselves.

Eg: https://play.rust-lang.org/?version=nightly&mode=debug&editi... do_something_with doesn't need to have any lifetimes from the allocator.

If by Zig-style allocators you specifically mean type-erased allocators, as a way to not have to parameterize everything on A:Allocator, then yes the equivalent in Rust would be a &'a dyn Allocator that has an infectious 'a lifetime parameter instead. Given the choice between an infectious type parameter and infectious lifetime parameter I'd take the former.

nicce · 1h ago
Additions are easy. By default they are wrapped, and you can make them explicit with checked_ methods.

Assuming that you are not using much recursion, you can eliminate most of the heap related memory panics by adding limited reservation checks for dynamic data, which is allocated based on user input/external data. You should also use statically sized types whennever possible. They are also faster.

codedokode · 1h ago
Wrapping on overflow is wrong because this is not the math we expect. As a result, errors and vulnerabilities occur (look at Linux kernel for example).
nicce · 1h ago
It depends on the context. Of course the result may cause vulnerabilities if the program logic in bad context depends on it. But yeah, generally I would agree.
PhilipRoman · 1h ago
>what are they supposed to do when there is no memory left

Well on Linux they are apparently supposed to return memory anyway and at some point in the future possibly SEGV your process when you happen to dereference some unrelated pointer.

pdimitar · 1h ago
Don't know about your parent poster but I didn't take it 100% literally. Obviously if there's no memory left then you crash; the kernel would likely murder your program half a second later anyway.

But for arithmetics Rust has non-aborting bound checking API, if my memory serves.

And that's what I'm trying hard to do in my Rust code f.ex. don't frivolously use `unwrap` or `expect`, ever. And just generally try hard to never use an API that can crash. You can write a few error branches that might never get triggered. It's not the end of the world.

wahern · 54s ago
Dealing with integer overflow is much more burdensome than dealing with allocation failure, IME. Relatively speaking, allocation failure is closer to file descriptor limits in terms of how it effects code structure. But then I mostly use C when I'm not using a scripting language. In languages like Rust and C++ there's alot of hidden allocation in the high-level libraries that seem to be popular.
arijun · 2h ago
`panic` isn’t really an error that you have to (or can) handle, it’s for unrecoverable errors. Sort of like C++ assertions.

Also there is the no_panic crate, which uses macros to require the compiler to prove that a given function cannot panic.

nicce · 2h ago
I would say that Segmentation Fault is better comparison with C++ :-D
marcosdumay · 1h ago
Well, kinda. It's more similar to RuntimeException in Java, in that there are times where you do actually want to catch and recover from them.

But on those places, you better know exactly what you are doing.

alexeldeib · 3h ago
that's kind of a thing with https://docs.rs/no-panic/latest/no_panic/ or no std and custom panic handlers.

not sure what the latest is in the space, if I recall there are some subtleties

zozbot234 · 2h ago
That's a neat hack, but it would be a lot nicer to have explicit support as part of the language.
kbolino · 1h ago
That's going to be difficult because the language itself requires panic support to properly implement indexing, slicing, and integer division. There are checked methods that can be used instead, but to truly eliminate panics, the ordinary operators would have to be banned when used with non-const arguments, and this restriction would have to propagate to all dependencies as well.
nicce · 1h ago
The problem is with false positives. Even if you clearly see that some function will never panic (but it uses some feature which may panic), compiler might not always see that. If compiler says that there are no panics, then there are no panics, but is it enough to add as part of the language if you need to mostly avoid using features that might panic?
dvt · 3h ago
Maybe contrarian, but imo the `Result` type, while kind of nice, still suffers from plenty of annoyances, including sometimes not working with the (manpages-approved) `dyn Error`, sometimes having to `into()` weird library errors that don't propagate properly, or worse: `map_err()` them; I mean, at this point, the `anyhow` crate is basically mandatory from an ergonomics standpoint in every Rust project I start. Also, `?` doesn't work in closures, etc.

So, while this is an improvement over C++ (and that is not saying much at all), it's still implemented in a pretty clumsy way.

singingboyo · 2h ago
There's some space for improvement, but really... not a lot? Result is a pretty basic type, sure, but needing to choose a dependency to get a nicer abstraction is not generally considered a problem for Rust. The stdlib is not really batteries included.

Doing error handling properly is hard, but it's a lot harder when error types lose information (integer/bool returns) or you can't really tell what errors you might get (exceptions, except for checked exceptions which have their own issues).

Sometimes error handling comes down to "tell the user", where all that info is not ideal. It's too verbose, and that's when you need anyhow.

In other cases where you need details, anyhow is terrible. Instead you want something like thiserror, or just roll your own error type. Then you keep a lot more information, which might allow for better handling. (HttpError or IoError - try a different server? ParseError - maybe a different parse format? etc.)

So I'm not sure it's that Result is clumsy, so much that there are a lot of ways to handle errors. So you have to pick a library to match your use case. That seems acceptable to me?

FWIW, errors not propagating via `?` is entirely a problem on the error type being propagated to. And `?` in closures does work, occasionally with some type annotating required.

ackfoobar · 2h ago
> the `anyhow` crate is basically mandatory from an ergonomics standpoint in every Rust project I start

If you use `anyhow`, then all you know is that the function may `Err`, but you do not know how - this is no better than calling a function that may `throw` any kind of `Throwable`. Not saying it's bad, it is just not that much different from the error handling in Kotlin or C#.

Yoric · 39m ago
Yeah, `anyhow` is basically Go error handling.

Better than C, sufficient in most cases if you're writing an app, to be avoided if you're writing a lib. There are alternatives such as `snafu` or `thiserror` that are better if you need to actually catch the error.

jbritton · 1h ago
I know a ‘C’ code base that treats all socket errors the same and just retries for a limited time. However there are errors that make no sense to retry, like invalid socket or socket not connected. It is necessary to know what socket error occurred. I like how the Posix API defines an errno and documents the values. Of course this depends on accurate documentation.
efnx · 2h ago
Yes. I prefer ‘snafu’ but there are a few, and you could always roll your own.
smj-edison · 1h ago
+1 for snafu. It lets you blend anyhow style errors for application code with precise errors for library code. .context/.with_context is also a lovely way to propagate errors between different Result types.
bonzini · 1h ago
How does that compare to "this error for libraries and anyhow for applications"?
smj-edison · 1h ago
You don't have to keep converting between error types :)
shepmaster · 2h ago
Yeah, with SNAFU I try to encourage people going all-in on very fine-grained error types. I love it (unsurprisingly).
maplant · 3h ago
? definitely works in closures, but it often takes a little finagling to get working, like specifying the return type of the closure or setting the return type of a collect to a Result<Vec<_>>

No comments yet

skrtskrt · 30m ago
A couple of those annoyances are just library developers being too lazy to give informative error types which is far from a Rust-specific problem
mdf · 3h ago
Generally, I agree the situation with errors is much better in Rust in the ways you describe. But, there are also panics which you can catch_unwind[1], set_hook[2] for, define a #[panic_handler][3] for, etc.

[1] https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

[2] https://doc.rust-lang.org/std/panic/fn.set_hook.html

[3] https://doc.rust-lang.org/nomicon/panic-handler.html

ekidd · 2h ago
Yeah, in anything but heavily multi-threaded servers, it's usually best to immediately crash on a panic. Panics don't mean "a normal error occurred", they mean, "This program is cursed and our fundamental assumptions are wrong." So it's normal for a unit test harness to catch panics. And you may occasionally catch them and kill an entire client connection, sort of the way Erlang handles major failures. But most programs should just exit immediately.
jasonjmcghee · 3h ago
unfortunately it's not so simple. that's the convention. depending on the library you're using it might be a special type of Error, or special type of Result, something needs to be transformed, `?` might not work in that case (unless you transform/map it), etc.

I like rust, but its not as clean in practice, as you describe

ryandv · 1h ago
There are patterns to address it such as creating your own Result type alias with the error type parameter (E) fixed to an error type you own:

    type Result<T> = result::Result<T, MyError>;

    #[derive(Debug)]
    enum MyError {
        IOError(String)
        // ...
    }
Your owned (i.e. not third-party) Error type is a sum type of error types that might be thrown by other libraries, with a newtype wrapper (`IOError`) on top.

Then implement the `From` trait to map errors from third-party libraries to your own custom Error space:

    impl From<io::Error> for MyError {
        fn from(e: io::Error) -> MyError {
            MyError::IOError(e.to_string())
        }
    }
Now you can convert any result into a single type that you control by transforming the errors:

    return sender
        .write_all(msg.as_bytes())
        .map_err(|e| e.into());
There is a little boilerplate and mapping between error spaces that is required but I don't find it that onerous.
koakuma-chan · 3h ago
You can use anyhow::Result, and the ? will work for any Error.
kccqzy · 1h ago
The Result type isn't really enough for fun and easy error handling. I usually also need to reach for libraries like anyhow https://docs.rs/anyhow/latest/anyhow/. Otherwise, you still need to think about the different error types returned by different libraries.

Back at Google, it was truly an error handling nirvana because they had StatusOr which makes sure that the error type is just Status, a standardized company-wide type that stills allows significant custom errors that map to standardized error categories.

0x1ceb00da · 1h ago
Proper error handling is the biggest problem in a vast majority of programs and rust makes that straightforward by providing a framework that works really well. I hate the `?` shortcut though. It's used horribly in many rust programs that I've seen because the programmers just use it as a half assed replacement for exceptions. Another gripe I have is that most library authors don't document what errors are returned in what situations and you're left making guesses or navigating through the library code to figure this out.
fpoling · 2h ago
Result type still requires quite a few lines of boilerplate if one needs to add custom data to it. And as a replacement of exceptions with automatic stack trace attachment it is relatively poor.

In any case I will take Rust Result over C++ mess at any time especially given that we have two C++, one with exception support and one without making code incompatible between two.

dabinat · 3h ago
I wish Option and Result weren’t exclusive. Sometimes a method can return an error, no result or a valid result. Some crates return an error for “no result”, which feels wrong to me. My solution is to wrap Result<Option>, but it still feels clunky.

I could of course create my own type for this, but then it won’t work with the ? operator.

Arnavion · 1h ago
Result<Option> is the correct way to represent this, and if you need further convincing, libstd uses it for the same reason: https://doc.rust-lang.org/stable/std/primitive.slice.html?se...
dicytea · 2h ago
> I could of course create my own type for this, but then it won’t work with the ? operator.

This is what the Try[^1] trait is aiming to solve, but it's not stabilized yet.

[^1]: https://rust-lang.github.io/rfcs/3058-try-trait-v2.html

atoav · 2h ago
I think Result<Option> is the way to go. It describes precisely that: was it Ok? if yes, was there a value?

I could imagine situations where an empty return value would constitute an Error, but in 99% of cases returning None would be better.

Result<Option> may feel clunky, but if I can give one recommendation when it comes to Rust, is that you should not value your own code-aesthetical feelings too much as it will lead to a lot of pain in many cases — work with the grain of the language not against it even if the result does not satisfy you. In this case I'd highly recommend just using Result<Option> and stop worrying about it.

You being able to compose/nest those base types and unwraping or matching them in different sections of your code is a strength not a weakness.

vjerancrnjak · 2h ago
This sounds valid. Lookup in a db can be something or nothing or error.

Just need a function that allows lifting option to result.

ryandrake · 1h ago
Error handling and propagation is one of those things I found the most irritating and struggled[1] with the most as I learned Rust, and to be honest, I'm still not sure I understand or like Rust's way. Decades of C++ and Python has strongly biased me towards the try/except pattern.

1: https://news.ycombinator.com/item?id=41543183

skrtskrt · 48m ago
there are answers in the thread you linked that show how easy and clean the error handling can be.

it can look just like a more-efficient `except` clauses with all the safety, clarity, and convenience that enums provide.

Here's an example:

* Implementing an error type with enums: https://git.deuxfleurs.fr/Deuxfleurs/garage/src/branch/main/... * Which derives from a more general error type with even more helpful enums: https://git.deuxfleurs.fr/Deuxfleurs/garage/src/branch/main/... * then some straightforward handling of the error: https://git.deuxfleurs.fr/Deuxfleurs/garage/src/branch/main/...

tubs · 3h ago
And panics?
90s_dev · 2h ago
I like so much about Rust.

But I hear compiling is too slow.

Is it a serious problem in practice?

conradludgate · 1h ago
It is slow, and yes it is a problem, but given that typical Rust code generally needs fewer full compiles to get working tests (with more time spent active in the editor, with an incremental compiler like Rust Analyzer) it usually balances out.

Cargo also has good caching out of the box. While cargo is not the best build system, it's an easy to use good system, so you generally get good compile times for development when you edit just one file. This is along made heavy use of with docker workflows like cargo-chef.

juliangmp · 2h ago
I can't speak for a bigger rust project, but my experience with C++ (mostly with cmake) is so awful that I don't think it can get any worse.

Like with any bigger C++ project there's like 3 build tools, two different packaging systems and likely one or even multiple code generators.

Seattle3503 · 2h ago
Absolutely, the compile times are the biggest drawback IMO. Everywhere I've been that built large systems in Rust eventually ends up spending a good amount of dev time trying to get CI/CD pipeline times to something sane.

Besides developer productivity it can be an issue when you need a critical fix to go out quickly and your pipelines take 60+ minutes.

lilyball · 2h ago
Don't use a single monolithic crate. Break your project up into multiple crates. Not only does this help with compile time (the individual crate compiles can be parallelized), it also tends to help with API design as well.
Seattle3503 · 1h ago
Every project I've worked on used a workspace with many crates. Generally that only gets you so far on large projects.
mixmastamyk · 1h ago
It compiles different files separately, right?

With some exceptions for core data structures, it seems that if you only modified a few files in a large project the total compilation time would be quick no matter how slow the compiler was.

conradludgate · 1h ago
Sorta. The "compilation unit" is a single crate, but rustc is now also parallel, and LLVM can also be configured to run in parallel IIRC.

Rust compile times have been improving over time as the compiler gets incrementally rewritten and optimised.

mynameisash · 2h ago
It depends on where you're coming from. For me, Rust has replaced a lot of Python code and a lot of C# code, so yes, the Rust compilation is slow by comparison. However, it really hasn't adversely affected (AFAICT) my/our iteration speed on projects, and there are aspects of Rust that have significantly sped things up (eg, compilation failures help detect bugs before they make it into code that we're testing/running).

Is it a serious problem? I'd say 'no', but YMMV.

kelnos · 2h ago
Compilation is indeed slow, and I do find it frustrating sometimes, but all the other benefits Rust brings more than make up for it in my book.
cmrdporcupine · 2h ago
I worked in the chromium C++ source tree for years and compiling there was orders of magnitude slower than any Rust source tree I've worked in so far.

Granted, there aren't any Rust projects that large yet, but I feel like compilation speeds are something that can be worked around with tooling (distributed build farms, etc.). C++'s lack of safety and a proclivity for "use after free" errors is harder to fix.

gpderetta · 19m ago
Are there rust projects that are within orders of magnitude of Chromium?
zozbot234 · 2h ago
People who say "Rust compiling is so slow" have never experienced what building large projects was like in the mid-1990s or so. It's totally fine. Besides, there's also https://xkcd.com/303/
creata · 2h ago
Or maybe they have experienced what it was like and they don't want to go back.
kelnos · 2h ago
Not really relevant. The benchmark is how other language toolchains perform today, not what they failed to do 30 years ago. I don't think we'd find it acceptable to go back to mid-'90s build times in other languages, so why should we be ok with it with something like Rust?
cmrdporcupine · 2h ago
abseil's "StatusOr" is roughly like Rust's Result type, and is what is used inside Google's C++ codebases (where exceptions are mostly forbidden)

https://github.com/abseil/abseil-cpp/blob/master/absl/status...

bena · 1h ago
Ok, I'm at like 0 knowledge on the Rust side, so bear that in mind. Also, to note that I'm genuinely curious about this answer.

Why can't I return an integer on error? What's preventing me from writing Rust like C++?

tczMUFlmoNk · 1h ago
You can write a Rust function that returns `i32` where a negative value indicates an error case. Nothing in Rust prevents you from doing that. But Rust does have facilities that may offer a nicer way of solving your underlying problem.

For instance, a common example of the "integer on error" pattern in other languages is `array.index_of(element)`, returning a non-negative index if found or a negative value if not found. In Rust, the return type of `Iterator::position` is instead `Option<usize>`. You can't accidentally forget to check whether it's present. You could still write your own `index_of(&self, element: &T) -> isize /* negative if not found */` if that's your preference.

https://doc.rust-lang.org/std/iter/trait.Iterator.html#metho...

bonzini · 1h ago
Nothing prevents you, you just get uglier code and more possibility of confusion.
thrwyexecbrain · 1h ago
The C++ code I write these days is actually pretty similar to Rust: everything is explicit, lots of strong types, very simple and clear lifetimes (arenas, pools), non-owning handles instead of pointers. The only difference in practice is that the build systems are different and that the Rust compiler is more helpful (both in catching bugs and reporting errors). Neither a huge deal if you have a proper build and testing setup and when everybody on your team is pretty experienced.

By the way, using "atoi" in a code snippet in 2025 and complaining that it is "not ideal" is, well, not ideal.

taylorallred · 59m ago
Cool that you're using areas/pools for lifetimes. Are you also using custom data structures or stl (out of curiosity)?
yodsanklai · 1h ago
> The C++ code I write these days

Meaning you're in a context where you have control on the C++ code you get to write. In my company, lots of people get to update code without strict guidelines. As a result, the code is going to be complex. I'd rather have a simpler and more restrictive language and I'll always favor Rust projects to C++ ones.

bluGill · 19m ago
That is easy to say today, but I guarantee in 30 year Rust will have rough edges too. People always want some new feature and eventually one comes in that cannot be accommodated nicely.

Of course it will probably not be as bad as C++, but still it will be complex and people will be looking for a simpler language.

jpc0 · 3h ago
Amazing example of how easy it is to get sucked into the rust love. Really sincerely these are really annoying parts of C++.

The conversation function is more language issue. I don’t think there is a simple way of creating a rust equivalent version because C++ has implicit conversions. You could probably create a C++ style turbofish though, parse<uint32_t>([your string]) and have it throw or return std::expected. But you would need to implement that yourself, unless there is some stdlib version I don’t know of.

Don’t conflate language features with library features.

And -Wconversion might be useful for this but I haven’t personally tried it since what Matt is describing with explicit types is the accepted best practice.

ujkiolp · 2h ago
meh, rust is still better cos it’s friendlier
jpc0 · 2h ago
I don’t disagree. Rust learnt a ton from C++.

I have my gripes with rust, more it’s ecosystem and community that the core language though. I won’t ever say it’s a worse language than C++.

kasajian · 2h ago
This seems a big silly. This is not a language issue. You can have a C++ library that does exactly all the things being shown here so that the application developer doesn't worry about. There would no C++ language features missing that would accomplish what you're able to do on the Rust side.

So is this really a language comparison, or what libraries are available for each language platform? If the latter, that's fine. But let's be clear about what the issue is. It's not the language, it's what libraries are included out of the box.

lytedev · 2h ago
The core of this argument taken to its extreme kind of makes the whole discussion pointless, right? All the languages can do all the things, so why bother differentiating them?

To entertain the argument, though, it may not be a language issue, but it certainly is a selling point for the language (which to me indicates a "language issue") to me if the language takes care of this "library" (or good defaults as I might call them) for you with no additional effort -- including tight compiler and tooling integration. That's not to say Rust always has good defaults, but I think the author's point is that if you compare them apples-to-oranges, it does highlight the different focuses and feature sets.

I'm not a C++ expert by any stretch, so it's certainly a possibility that such a library exists that makes Rust's type system obsolete in this discussion around correctness, but I'm not aware of it. And I would be incredibly surprised if it held its ground in comparison to Rust in every respect!

LinXitoW · 32m ago
Sure, you can emulate some of the features and hope that everyone using your library is doing it "right". Just like you could just use a dynamic language, tag every variable with a type, and hope everyone using your library does the MANUAL work of always doing it correct. Guess we don't need types either.

And while we're at it, why not use assembly? It's all just "syntactic sugar" over bits, doesn't make any difference, right?

Etheryte · 2h ago
Just like language shapes the way we think and talk about things, programming languages shape both what libraries are written and how. You could write anything in anything so long as it's Turing complete, but in real life we see clearly that certain design decisions at the language level either advantage or disadvantage certain types of solutions. Everyone could in theory write C without any memory issues, but we all know how that turns out in practice. The language matters.
sdenton4 · 2h ago
If the default is a loaded gun pointed at your foot, you're going to end up with lots of people missing a foot. "just git gud" isn't a solution.
cbsmith · 2h ago
That's an entirely different line of reasoning from the article though, and "just git gud" isn't really the solution here any more than it is to use Rust. There are facilities for avoiding these problems that you don't have to learn how to construct yourself in either language.
cbsmith · 2h ago
Yeah, I kept thinking, "doesn't mp-units basically address this entirely"?
grumbel · 3h ago
There is '-Wconversion' to catch things like this. It will however not trigger in this specific case since g++ assumes converting 1000.0 to 1000 is ok due to no loss in precision.

Quantity(100) is counterproductive here, as that doesn't narrow the type, it does the opposite, it casts whatever value is given to the type, so even Quantity(100.5) will still work, while just plain 100.5 would have given an error with '-Wconversion'.

Arnavion · 3h ago
The reason to introduce the Quantity wrapper is to not be able to swap the quantity and price arguments.
b5n · 2h ago
> -Wconversion ... assumes converting 1000.0 to 1000 is ok due to no loss in precision.

Additionally, `clang-tidy` catches this via `bugprone-narrowing-conversions` and your linter will alert if properly configured.

kelnos · 2h ago
My opinion is that if you need to run extra tools/linters in order to catch basic errors, the language & its compiler are not doing enough to protect me from correctness bugs.

I do run clippy on my Rust projects, but that's a matter of style and readability, not correctness (for the most part!).

throwaway76455 · 10m ago
Setting up clang-tidy for your IDE isn't really any more trouble than setting up a LSP. If you want the compiler/linter/whatever to reject valid code to protect you from yourself, there are tools you can use for that. Dismissing them just because they aren't part of the language (what, do you expect ISO C++ to enforce clang-tidy usage?) is silly.
b5n · 1h ago
There's a bit more nuance here than 'basic errors', and modern c compilers offer a lot of options _if you need to use them_.

I appreciate that there are guardrails in a tool like rust, I also appreciate that sharp tools like c exist, they both have advantages.

jpc0 · 2h ago
How much of what Rust the language checks is actually linter checks implemented in the compiler?

Conversions may be fine and even useful in many cases, in this case it isn’t. Converting to std::variant or std::optional are some of those cases that are really nice.

GardenLetter27 · 3h ago
It's a shame Rust doesn't have keyword arguments or named tuples to make handling some of these things easier without Args/Options structs boilerplate.
frankus · 2h ago
I work all day in Swift (which makes you go out of your way to omit argument labels) and I'm surprised they aren't more common.
jsat · 2h ago
Had the same thought... It's backwards that any language isn't using named parameters at this point.
Ygg2 · 1h ago
Named parameters do come with a large footgun. Renaming your parameters is a breaking change.

Especially if you're coming from different langs.

shpongled · 3h ago
Yep, I would love anonymous record types, ala StandardML/OCaml
writebetterc · 3h ago
Yes, Rust is better. Implicit numeric conversion is terrible. However, don't use atoi if you're writing C++ :-). The STL has conversion functions that will throw, so separate problem.
titzer · 3h ago
> Implicit numeric conversion is terrible.

It's bad if it alters values (e.g. rounding). Promotion from one number representation to another (as long as it preserves values) isn't bad. This is trickier than it might seem, but Virgil has a good take on this (https://github.com/titzer/virgil/blob/master/doc/tutorial/Nu...). Essentially, it only implicitly promotes values in ways that don't lose numeric information and thus are always reversible.

In the example, Virgil won't let you pass "1000.00" to an integer argument, but will let you pass "100" to the double argument.

plus · 3h ago
Aside from the obvious bit size changes (e.g. i8 -> i16 -> i32 -> i64, or f32 -> f64), there is no "hierarchy" of types. Not all ints are representable as floats. u64 can represent up to 2^64 - 1, but f64 can only represent up to 2^53 with integer-level precision. This issue may be subtle, but Rust is all about preventing subtle footguns, so it does not let you automatically "promote" integers to float - you must be explicit (though usually all you need is an `as f64` to convert).
mananaysiempre · 2h ago
> Aside from the obvious bit size changes (e.g. i8 -> i16 -> i32 -> i64, or f32 -> f64), there is no "hierarchy" of types.

Depends on what you want from such a hierarchy, of course, but there is for example an injection i32 -> f64 (and if you consider the i32 operations to be undefined on overflow, then it’s also a homomorphism wrt addition and multiplication). For a more general view, various Schemes’ takes on the “numeric tower” are informative.

favorited · 3h ago
Side note, if anyone is interested in hearing more from Matt, he has a programming podcast with Ben Rady called Two's Complement.

https://www.twoscomplement.org

badbart14 · 3h ago
+1, especially loved the episode from a couple months back about using AI tools in development. Really got me thinking differently about the role of AI in a developer's workflow and how software development will evolve.
penguin_booze · 2h ago
I can't see the publish date on the episodes.
jsat · 2h ago
I see an article about how strict typing is better, but what would really be nice here is named parameters. I never want to go back to anonymous parameters.
kelnos · 2h ago
Yes, this is one of the few things that I think was a big mistake in Rust's language design. I used to do a lot of Scala, and really liked named parameters there.

I suppose it could still be added in the future; there are probably several syntax options that would be fully backward-compatible, without even needing a new Rust edition.

sophacles · 22m ago
Why? In 2025 we have tooling available for most every editor that will annotate that information into the display without needing them present in the file. When I autocomplete a function name, all the parameters are there for me to fill in, and annotated into the display afterwards. It seems like an unnecessary step to reify it and force the bytes to be present in the the saved file.
codedokode · 1h ago
When there are 3-4 parameters it is too much trouble to write the names.
noitpmeder · 15m ago
Not OP, but I imagine he's arguing for something like python's optional named arguments.
antirez · 51m ago
You can have two arguments that are semantically as distinct and important as quantity and price and be both integers, and if you swap them is a big issue anyway. And you would be forced, if you like this kind of programming, to create distinct types anyway. But I never trust this kind of "toy" defensive programming. The value comes from testing very well the code, from a rigorous quality focus.
markus_zhang · 3h ago
What if we have a C that removes the quirks without adding too much brain drain?

So no implicit type conversions, safer strings, etc.

LorenDB · 3h ago
Walter Bright will probably show up soon to plug D's BetterC mode, but if he doesn't, still check it out.

https://dlang.org/spec/betterc.html

cogman10 · 3h ago
I've seen this concept tried a few times (For example, MS tried it with Managed C++). The inevitable problem you run into is any such language isn't C++. Because of that, you end up needing to ask, "why pick this unpopular half C/C++ implementation and not Rust/go/D/Java/python/common lisp/haskell."

A big hard to solve problem is you are likely using a C because of the ecosystem and/or the performance characteristics. Because of the C header/macro situation that becomes just a huge headache. All the sudden you can't bring in, say, boost because the header uses the quirks excluded from your smaller C language.

o11c · 3h ago
I too have been thinking a lot about a minimum viable improvement over C. This requires actually being able to incrementally port your code across:

* "No implicit type conversions" is trivial, and hardly worth mentioning. Trapping on both signed and unsigned overflow is viable but for hash-like code opting in to wrapping is important.

* "Safer strings" means completely different things to different people. Unfortunately, the need to support porting to the new language means there is little we can do by default, given the huge amount of existing code. We can however, add new string types that act relatively uniformly so that the code can be ported incrementally.

* For the particular case of arrays, remember that there are at least 3 different ways to compute its length (sentinel, size, end-pointer). All of these will need proper typing support. Particularly remember functions that take things like `(begin, middle end)`, or `(len, arr1[len], arr2[len])`.

* Support for nontrivial trailing array-or-other datums, and also other kinds of "multiple objects packed within a single allocation", is essential. Again, most attempted replacements fail badly.

* Unions, unfortunately, will require much fixing. Most only need a tag logic (or else replacement with bitcasting), but `sigval` and others like it are fundamentally global in nature.

* `va_list` is also essential to support since it is very widely used.

* The lack of proper C99 floating-point support, even in $CURRENTYEAR, means that compile-to-C implementations will not be able to support it properly either, even if the relevant operations are all properly defined in the new frontend to take an extra "rounding mode" argument. Note that the platform ABI matters here.

* There are quite a few things that macros are used for, but ultimately this probably is a finite set so should be possible to automatically convert with a SMOC.

Failure to provide a good porting story is the #1 mistake most new languages make.

wffurr · 3h ago
This seems like such an obvious thing to have - where is it? Zig, Odin, etc. all seem much more ambitious.
steveklabnik · 3h ago
There have been attempts over the years. See here, a decade ago: https://blog.regehr.org/archives/1287

> eventually I came to the depressing conclusion that there’s no way to get a group of C experts — even if they are knowledgable, intelligent, and otherwise reasonable — to agree on the Friendly C dialect. There are just too many variations, each with its own set of performance tradeoffs, for consensus to be possible.

IshKebab · 3h ago
I think if you are going to fix C's footguns you'll have to change so much you end up with a totally new language anyway, and then why not be ambitious? It costs a lot to learn a new language and people aren't going to bother if the only benefit it brings is things that can sort of mostly be caught with compiler warnings and static analysis.
zyedidia · 3h ago
I think the only "C replacement" that is comparable in complexity to C is [Hare](https://harelang.org/), but several shortcomings make it unsuitable as an actual C replacement in many cases (little/no multithreading, no support for macOS/Windows, no LLVM or GCC support, etc.).
Zambyte · 52m ago
And why do you think Zig (and Odin, but I'm not really familiar with that one) is not comparable in complexity to C? If you start with C, replace the preprocessor language with the host language, replace undefined behavior with illegal behavior (panics in debug builds), add different pointer types for different types of pointers (single object pointers, many object pointers, fat many object pointers (slices), nullable pointers), and make a few syntactic changes (types go after the names of values in declarations, pointer dereference is a postfix operator, add defer to move expressions like deallocation to the end of the scope) and write a new standard library, you pretty much have Zig.
mamcx · 3h ago
If you can live without much of the ecosystem (specially if has async) there is way to write rust very simple.

The core of Rust is actually very simple: Struct, Enum, Functions, Traits.

nitwit005 · 2h ago
Because it's easier to add a warning or error. Don't like implicit conversions? Add a compiler flag, and the issue is basically gone.

Safer strings is harder, as it gets into the general memory safety problem, but people have tried adding safer variants of all the classic functions, and warnings around them.

Certhas · 56m ago
Maybe just unsafe rust?
dlachausse · 3h ago
Swift is really great these days and supports Windows and Linux. It almost feels like a scripting language other than the compile time of course.
kelnos · 1h ago
I still have a hard time adopting a language/ecosystem that was originally tied to a particular platform, and is still "owned" by the owners of that platform.

Sun actually did it right with Java, recognizing that if they mainly targeted SunOS/Solaris, no one would use it. And even though Oracle owns it now, it's not really feasible for them to make it proprietary.

Apple didn't care about other platforms (as usual) for quite a long time in Swift's history. Microsoft was for years actively hostile toward attempts to run .NET programs on platforms other than Windows. Regardless of Apple's or MS's current stance, I can't see myself ever bothering with Swift or C#/F#/etc. There are too many other great choices with broad platform and community support, that aren't closely tied to a corporation.

hmry · 31m ago
.NET recently had a (very) minor controversy for inserting what amounts to a GitHub Copilot ad into their docs. So yeah, it sure feels like "once a corporate language, always a corporate language", even if it's transferred to a nominally independent org. It might not be entirely rational, but I certainly feel uncomfortable using Swift or .NET.
smt88 · 3h ago
There is no universe where I'm doing to use Apple tooling on a day to day basis. Their DX is the worst among big tech companies by far.
dlachausse · 3h ago
They have quite robust command line tooling and a good VS Code plugin now. You don’t need to use Xcode anymore for Swift.
alexchamberlain · 3h ago
I'm inferring that you think Rust adds too much brain drain? If so, what?
GardenLetter27 · 3h ago
The borrow checker rejects loads of sound programs - just read https://rust-unofficial.github.io/too-many-lists/

Aliasing rules can also be problematic in some circumstances (but also beneficial for compiler optimisations).

And the orphan rule is also quite restrictive for adapting imported types, if you're coming from an interpreted language.

https://loglog.games/blog/leaving-rust-gamedev/ sums up the main issues nicely tbh.

IshKebab · 3h ago
> The borrow checker rejects loads of sound programs

I bet assembly programmers said the same about C!

Every language has relatively minor issues like these. Seriously pick a language and I can make a similar list. For C it will be a very long list!

leonheld · 2h ago
I love Rust, but I after doing it for a little while, I completely understand the "brain drain" aspect... yes, I get significantly better programs, but it is tiring to fight the borrow-checker sometimes. Heck, I currently am procrastinating instead of going into the ring.

Anyhow, I won't go back to C++ land. Better this than whatever arcane, 1000-line, template-hell error message that kept me fed when I was there.

morning-coffee · 3h ago
Reading "The Rust Book" sold me on Rust (after programming in C++ for over 20 years)
mixmastamyk · 1h ago
Am about finished, but several chapters near the end seriously put me to sleep. Will try again some other day I suppose.
gbin · 1h ago
Interestingly in Rust I would immediately use an Enum for the Order! Way more powerful semantically.
adamc · 3h ago
Coming from python (or Common Lisp, or...), I wasn't too impressed. In Python I normally make args for any function with more than a couple be keyword arguments, which guarantees that you are aware of how the arguments are being mapped to inputs.

Even Rust's types aren't going to help you if two arguments simply have the same types.

rq1 · 2h ago
Just create dummy wrappers to make a type level distinction. A Height and a a Width can be two separate types even if they’re only floats basically.

Or another (dummy) example transfer(accountA, accountB). Make two types that wrap the same type but one being a TargetAccount and the other SourceAccount.

Use the type system to help you, don’t fight it.

jpc0 · 2h ago
Do you really want width and height or do you actually want dimensions or size? Same with transfer, maybe you wanted a transaction that gets executed. Worst case here use a builder with explicit function names.
rq1 · 1h ago
I don’t really understand your point there.

Sound type systems are equivalent to proof systems.

You can use them to design data structures where their mere eventual existence guarantee the coherence and validity of your program’s state.

The basic example is “Fin n” that carries at compile time the proof that you made the necessary bounds checks at runtime or by construction that you never exceeded some bound.

Some languages allow you to build entire type level state machines! (eg. to represent these transactions and transitions)

tumdum_ · 1h ago
The one thing that sold me on Rust was that I no longer had to chase down heisenbugs caused by memory corruption.
skywal_l · 2h ago
I love his videos on computerphile. One was just dropped a few hours ago: https://www.youtube.com/watch?v=1su3lAh-k4o
mattgodbolt · 1h ago
Wow that guy, eh? He seems to turn up everywhere :D
ModernMech · 3h ago
What sold me on Rust is that I'm a very bad programmer and I make a lot of mistakes. Given C++, I can't help but hold things wrong and shoot myself in the foot. My media C++ coding session is me writing code, getting a segfault immediately, and then spending time chasing down the reason for that happening, rinse and repeat.

My median Rust coding session isn't much different, I also write code that doesn't work, but it's caught by the compiler. Now, most people call this "fighting with the borrow checker" but I call it "avoiding segfaults before they happen" because when I finally get through the compiler my code usually "just works". It's that magical property Haskell has, Rust also has it to a large extent.

So then what's different about Rust vs. C++? Well Rust actually provides me a path to get to a working program whereas C++ just leaves me with an error message and a treasure map.

What this means is that although I'm a bad programmer, Rust gives me the support I need to build quite large programs on my own. And that extends to the crate ecosystem as well, where they make it very easy to build and link third party libraries, whereas with C++ ld just tells you that it had a problem and you're left on your own to figure out exactly what.

jpc0 · 2h ago
Using your media example since I have a decent amount of experience there. Did you just use off the shelf libraries, because effectively all the libraries are written in or expose a C api. So now you not only need to deal with Rust, you need to also deal with rust ffi.

There are some places I won’t be excited to use rust, and media heavy code is one of those places…

sophacles · 15m ago
Given that the second paragraph starts with "my median rust..." i assume the "media C++" is actually a typo for "median C++".
hacker_homie · 2h ago
Wconversion And werror?
mempko · 2h ago
Rust does seem to have a lot of nice features. My biggest blocker for me going to Rust from C++ is that C++ has much better support for generic programming. And now that Concepts have landed, I'm not aware of any language that can compete in this area.
atemerev · 3h ago
Right. I attempted using Rust for trading-related code as well. However, I failed to write a dynamically linked always sorted order book where you can splice orders in the middle. It is just too dynamic for Rust. Borrow checker killed me.

And don't get me started on dynamic graphs.

I would happily use Rust over C++ if it had all other improvements but similar memory management. I am completely unproductive with Rust model.

kelnos · 1h ago
The nice thing is that you can always drop down to unsafe and use raw pointers if your data structure is truly not suited to Rust's ownership rules.

And while unsafe Rust does have some gotchas that vanilla modern C++ does not, I would much rather have a 99% memory-safe code base in Rust than a 100% "who knows" code base in C++.

atemerev · 33s ago
I have read the "too many linked lists" story and I think the other commenters here are right; the less pointers the better. Even with unsafe, there's just too much ceremony.
0x1ceb00da · 1h ago
> Borrow checker killed me.

You gotta get your timing right. Parry, parry, and then stab.

sunshowers · 3h ago
I apologize for the naive question, but that sounds like a heap?
jpc0 · 2h ago
In my experience you need to approach this with vec or arrays of some sort and pass indices around… “We have pointers at home” behaviour. This is fine but coming from C++ it definitely feels weird…
bigstrat2003 · 2h ago
Why not just use pointers? Rust has them, they aren't evil or anything. If you need to make a data structure that isn't feasible with references due to the borrow checker (such as a linked list), there's absolutely nothing wrong with using pointers.
sunshowers · 1h ago
I agree in general Rust makes you use arrays and indexes, but heaps are traditionally implemented that way in any language.
hacker_homie · 2h ago
I have run into similar issues trying to build real applications. You end up spending more time arguing with the borrow checker than writing code.
lytedev · 2h ago
I think this is true initially and Rust didn't "click" for me for a long time.

But once you are _maintaining_ applications, man it really does feel like absolute magic. It's amazing how worry-free it feels in many respects.

Plus, once you do embrace it, become familiar, and start forward-thinking about these things, especially in areas that aren't every-nanosecond-counts performance-wise and can simply `Arc<>` and `.clone()` where you need to, it is really quite lovely and you do dramatically less fighting.

Rust is still missing a lot of features that other more-modern languages have, no doubt, but it's been a great ride in my experience.

skippyboxedhero · 1h ago
Using reference counts is a real issue.

The idea with Rust is that you get safety...not that you get safety at the cost of performance. The language forces you into paying a performance cost for using patterns when it is relatively easy for a human to reason about safety (imo).

You can use `unsafe` but you naturally ask yourself why I am using Rust (not rational, but true). You can use lifetimes but, personally, every time I have tried to use them I haven't been able to indicate to the compiler that my code is actually safe.

In particular, the protections for double-free and free before use are extremely limiting, and it is possible to reason about these particular bugs in other ways (i.e. defer in Go and Zig) in a way that doesn't force you to change the way you code.

Rust is good in many ways but the specific problem mentioned at the top of this chain is a big issue. Just saying: don't use this type of data structure unless you pay performance cost isn't an actual solution to the problem. The problem with Rust is that it tries to force safety but doesn't have good ways for devs to tell the compiler code is safe...that is a fundamental weakness.

I use Rust quite a bit, it isn't a terrible language and is worth learning but these are big issues. I would have reservations using the language in my own company, rather than someone else's, and if I need to manage memory then I would look elsewhere atm. Due to the size of the community, it is very hard not to use Rust too (for example, Zig is great...but no-one uses it).

lytedev · 1h ago
The idea with rust is that you _can_ have safety with no performance cost if you need it, but depending on what you're building, of course, that may imply extra work.

The pragmatism of Rust means that you can use reference counting if it suits your use case.

Unsafe also doesn't mean throwing out the Rustiness of Rust, but others have written more extensively about that and I have no personal experience with it.

> The problem with Rust is that it tries to force safety but doesn't have good ways for devs to tell the compiler code is safe...that is a fundamental weakness.

My understanding is that this is the purpose of unsafe, but again, I can't argue against these points from a standpoint of experience, having stuck pretty strictly to safe Rust.

Definitely agree that there are issues with the language, no argument there! So do the maintainers!

> if I need to manage memory then I would look elsewhere atm

Haha I have the exact opposite feeling! I wouldn't try to manage memory any other way, and I'm guessing it's because memory management is more intuitive and well understood by you than by me. I'm lazy and very much like having the compiler do the bulk of the thinking for me. I'm also happy that Rust allows for folks like me to pay a little performance cost and do things a little bit easier while maintaining correctness. For the turbo-coders out there that want the speed and the correctness, Rust has the capability, but depending on your use case (like linked lists) it can definitely be more difficult to express correctness to the compiler.

skippyboxedhero · 37m ago
Agree, that is the purpose of unsafe but there is a degree of irrationality there, which I am guilty of, about using unsafe in Rust. I also worry about unsafe leaking if I am using raw pointer on a struct...but stdlib uses a lot of unsafe code, so I should be too.

I think the issue that people have is that they come into Rust with the expectation that these problems are actually solved. As I said, it would be nice if lifetimes weren't so impossible to use.

The compiler isn't doing the thinking if you have to change your code so the compiler is happy. The problem with Rust is too much thinking: you try something, compiler complains, what is the issue here, can i try this, still complain, what about this, etc. There are specific categories of bugs that Rust is trying to fix that don't require the changes that Rust requires in order to ensure correctness...if you use reference counter, you can have more bugs.

codedokode · 2h ago
What about catching integer overflow? Free open-source languages still cannot do it unlike they commercial competitors like Swift?
lytedev · 2h ago
I'm not sure if this is what you mean, exactly, but Rust indeed catches this at compile time.

https://play.rust-lang.org/?version=stable&mode=debug&editio... https://play.rust-lang.org/?version=stable&mode=debug&editio...

codedokode · 1h ago
I meant panic if during any addition (including in runtime) an overflow occurs.
genrilz · 38m ago
If you obscure the implementation a bit, you can change GP's example to a runtime overflow [0]. Note that by default the checks will only occur when using the unoptimized development profile. If you want your optimized release build to also have checks, you can put 'overflow-checks = true' in the '[profile.release]' section of your cargo.toml file [1].

  [0]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=847dc401e16fdff14ecf3724a3b15a93
  [1]: https://doc.rust-lang.org/cargo/reference/profiles.html
trealira · 42m ago
You can set a flag for that: https://doc.rust-lang.org/rustc/codegen-options/index.html#o...

By default, they're on during debug mode and off in release mode.

kelnos · 1h ago
Rust does have checked arithmetic operations (that return Result), but you have to explicitly opt in to them, of course, and they're not as ergonomic to use as regular arithmetic.
trealira · 45m ago
But, by default, normal arithmetic operations trap on overflow in debug mode, although they wrap with optimizations on.
z_open · 1h ago
assembly catches integer overflow. You just need to check the flag.