News for hackers. Stuff that matters.
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @09:14AM (#27164898)
Rant disclaimer. Proceed at your own risk.

I want to like Rust, if only because anything has to be better than C++. C++ is godawful and it sucks that all these decades later it’s what serious big software is written in.

But I haven’t found the explanation of Rust and it’s trade offs and philosophy written by someone who can write serious Haskell and Lisp and C++ and is like “Rust. This is the way. Here’s how and why.”

I’m sure there are much better blog posts than this one that shed light on how parametric as opposed to ad-hoc polymorphism is natural in Rust with no runtime cost. Or how Rust’s nested angle-bracket hell to get a pointer to a piece of memory is actually a deep and profound algebra that exposes std::move for the fraud it actually is or whatever.

Where do I find the explanation of why Rust is less awful than C++ written by someone who has written a lot of C++ out of necessity, doesn’t take non-browser JS seriously, doesn’t think 8 boxes need kube, doesn’t stand to make consulting revenue off having been involved in Cargo, and generally uses C++/Python because they’ve got work to do?

Where do I go to see the light as someone who has some idea how brilliant Eich is and also knows how ridiculous it is to use JavaScript when you’ve got an alternative better than Lua? (I’ve written a JavaScript compiler, I know how unfortunate node.js and Electron are).

I want to be sold! Sell me!

Re:Things you can’t do in Rust (and what to do instead) by simias on Saturday May 15, 2021 @10:43AM (#27165637)
When my Rust code successfully compiles, it usually works. Frankly in terms of user experience it's selling point #1. I could talk about the borrow checker, trait-based generics, native build system and dependency management, performance, relative ease of writing multithreaded code etc... But thinking about it the thing I like the most about coding in Rust is how hard I can lean onto the compiler and type system to spot mistakes and let me know about them.

C++ is not even close in that respect. Duck typed generics, lack of borrow checker, lack of sync/send markers for multithreaded code, easy-to-abuse overloading (that's even abused in the standard library, so there's no escaping it), legacy cruft that springs up in unexpected places, non hygienic macros, exceptions and frankly I could go on for quite a while.

I think for some of us Rust is effectively the promised land. I learned some Lisp and Haskell but I could never really get into them seriously because despite some cool language features I just don't like paying the performance costs of a heavy runtime, dynamic typing and garbage collection. So instead it was C and C++ for better or worse. But then Rust came out and said "hey, how about having your cake and eating it too?" and I never looked back.

But of course many people don't share the same objectives. If Haskell and Common Lisp are what you consider to be your baseline I can definitely see how Rust's very strict type system would be seen as an annoyance, especially if you don't mind paying some runtime performance cost for the sake of simplicity and speed of development.

Re:Things you can’t do in Rust (and what to do instead) by jvanderbot on Saturday May 15, 2021 @04:04PM (#27168497)
Long time C++ user here.

Precisely right (for me!): It is easier to get to compile because it is easier for me to express and easier to debug type / syntax problems. Once compiled, it has a very high probability of just working.

I'll add that the exercise of learning rust has distilled the lessons learned in writing "good" C and C++ into a language that has few other ways of doing things. It's like someone is guiding me through good multi-threaded, memory management, and type design practices in C++ every time I work on a Rust project.

This experience absolutely translates back when I'm working on C++ and C.

Rust has huge potential it it can keep its libraries "upstream" of other languages. C is king of providing a one-implementation-to-many-languages (though API wrapping). If Rust can accomplish that, it'll be my language of choice. As much as I love the Unix philosophy of many interacting programs, the reality is for most systems that dynamic or static linking is how things interact.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:05AM (#27165836)
You seem like someone who could write the blog post I'm looking for.
Re:Things you can’t do in Rust (and what to do instead) by simias on Saturday May 15, 2021 @12:26PM (#27166592)
I appreciate the encouragement! Maybe I will, but first I need to write a custom blogging system. In Rust of course.
Re:Things you can’t do in Rust (and what to do instead) by secondcoming on Saturday May 15, 2021 @12:35PM (#27166675)
> When my Rust code successfully compiles, it usually works.

I think it was on a previous HN story where Rust programmers claimed that to get around borrow checker errors they just clone things. Now, the code may compile and technically be correct, but it hardly exemplifies the attention to detail normally required by a systems engineer.

Re:Things you can’t do in Rust (and what to do instead) by simias on Saturday May 15, 2021 @12:45PM (#27166768)
I admit that I sometimes do this myself, but it's usually a last resort when I deem that a more elegant solution would probably end up being a lot more complicated and probably not a whole lot more efficient since the cloned data is only a few bytes. I use Rust on embedded devices with weak CPUs and only a hundred megs of RAM so I tend to be careful with cloning. Dealing with a lot of cloned data is also a good recipe to end up with inconsistent internal state.

It may be a bit of a No True Scotsman but in my experience hanging in Rust IRC channels and similar places, the devs who tend to clone and slap `Rc<RefCell<_>>` all over the place tend to be those who come from garbage collected languages, simply because they're really not used to thinking about ownership.

People who come from C, C++ and other non-GC languages are effectively already used to dealing with ownership and lifetimes, it's just that in those languages it's up to the developer to keep track of them. In terms of overall architecture I don't find that I write Rust much differently from C++, I use RAII most of the time and when that doesn't work out I'll carefully chose between cloning or some smart pointer/container.

IMO Reference counting and cloning should be the exception, not the rule, and I'd go as far as saying that if you find yourself cloning and boxing data all over the place in your Rust application you're either working on a very atypical application or you're doing it somewhat wrong.

Re:Things you can’t do in Rust (and what to do instead) by stouset on Saturday May 15, 2021 @05:56PM (#27169386)
As a Rust proponent I’d agree with this take 100%.

There are a lot of programmers who approach new languages by trying to write in the style of their previous language. That’s not really optimal, but it can get you up and running quickly producing passable results for a wide variety of (previous, next) language pairs.

Rust is not one of these languages. If you don’t try to “get” Rust and continue working across the grain, you’re going to have a rough time of things. Rust brings along an entirely new concept of explicit ownership that’s implicit in other languages, and if you simply try to push forward without internalizing those restrictions (and understanding their implications on how to structure your programs), the Rust compiler will never stop pushing back against you.

While there are legitimate reasons to need Rc<RefCell<_>>, to Box things, and to clone(), the vast majority of Rust code doesn’t need to fall back on them. If you find yourself instinctively and repeatedly reaching for these as a quick workaround for borrow checker complaints, it’s going to be much better in both the long and medium term to try and understand what the compiler is trying to tell you about your overall approach to design.

This is, I think, the biggest area where Rust evangelists can make some big strides. There are a lot of program designs that compile just fine in other languages but that Rust rejects (or pushes back against) for Very Good Reasons. And getting new developers over that hurdle where they understand how to internalize enough about ownership upfront that they can come up with approaches that work with the grain is a hard problem, and I’m not sure how to solve it. There’s a moment where something clicks and Rust goes from being a fight against the borrow checker to something where your designs just work out of the gate and I don’t know how to get that click to happen quicker.

Re:Things you can’t do in Rust (and what to do instead) by ben-schaaf on Saturday May 15, 2021 @01:01PM (#27166910)
> I don't find that I write Rust much differently from C++

Same here, though I do find myself deviating sometimes. Specifically there are cases in C++ where I could write code that makes less copies or handles data more efficiently but I don't because the approach would be more error prone. In rust these more risky approaches simply result in having more compiler errors instead of crashes or other runtime bugs.

Re:Things you can’t do in Rust (and what to do instead) by iudqnolq on Monday May 17, 2021 @09:08AM (#27182962)
> IMO Reference counting and cloning should be the exception, not the rule, and I'd go as far as saying that if you find yourself cloning and boxing data all over the place in your Rust application you're either working on a very atypical application or you're doing it somewhat wrong.

I strongly disagree. For example, I'm working on a project that shells out to a command line program to get a graph structure, and then computes things based on that structure. I want the code that traverses the graph to be efficient, but a handful of clones is trivial compared to opening a subprocess. In my case the clones are in the constant part of the big O.

Sometimes clones can let you have a more efficient algorithm as well. Reference counting is pervasive in async primitives, and (for very specific io-bound usecases) async can sometimes be more efficient.

It comes down to knowing your domain, althorighms, data, constraints, etc. and picking the right choice. I don't think you can say Arc is always a sign of a mediocre programmer.

I've never programmed embedded, but it makes sense that you've got strong memory constraints. One thing I like about Rust though is that there's a strong culture that just because you have to walk uphill through the snow on a tiny device doesn't mean you get to look down on those of us who get to run our code on a server.

Re:Things you can’t do in Rust (and what to do instead) by matklad on Saturday May 15, 2021 @10:30AM (#27165541)
It seems like in your case the easiest path might be to learn how the language works and see it for yourself. Otherwise, I think these posts are roughly in the genre you want:

* http://dtrace.org/blogs/bmc/2018/09/18/falling-in-love-with-...

* http://dtrace.org/blogs/bmc/2020/10/11/rust-after-the-honeym...

* https://gregoryszorc.com/blog/2021/04/13/rust-is-for-profess...

Re:Things you can’t do in Rust (and what to do instead) by stevenhuang on Saturday May 15, 2021 @11:55AM (#27166328)
That last article is a great comprehensive summary of Rust's features. Will be passing that around, thanks.
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:06AM (#27165843)
Bookmarked. Thank you!
Re:Things you can’t do in Rust (and what to do instead) by devit on Saturday May 15, 2021 @09:28AM (#27165015)
It's the only language existing that is memory safe and provides zero cost abstraction to the CPU capabilities (i.e. no mandatory GC, values don't need to be boxed, ability to mutate memory).

The only limitation that may not eventually be removed is the lack of dependent types (although you can kind of emulate them by lifting terms to the type level and using lifetimes to represent variables).

C++ is not memory safe, Lisp has no type system and Haskell has GC, all values are boxed in a closure and it cannot mutate memory safely, so none of these languages are even in contention.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @09:32AM (#27165053)
C++ compiled by clang-12, with clang-tidy and cppcheck turned all the way up, with everything owned by a std::unique_ptr, run through ASAN, UBSAN, TSAN etc (which seems to build about as fast as Rust) lets what by that Rust catches?

I’m not being sarcastic, in all earnestness educate me!

Re:Things you can’t do in Rust (and what to do instead) by CJefferson on Saturday May 15, 2021 @09:42AM (#27165140)
There are, for me, two problems with ASAN and friends:

1) it requires a later execution, rather than your code failing to even compile.

2) it requires excellent and complete tests, probably with quality fuzzing, as often the corner cases (like hiting buffer size limit) is where problems occur.

For me, the argument for Rust is exactly that it let me (mostly) get rid of ASAN and UBSAN and valgrind and friends, which I consider required for C++.

The other big advantage of Rust is package management, with I feel C and C++ are awful at, particularly if you want to release for Linux, Mac and Windows.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:08AM (#27165880)
The package management point is completely on point. CMake blows and mixing in autotools makes it worse.

I think I consider the need to run under ASAN in a configuration that gets code coverage a feature rather than a bug. It's stupid monkey-brain stuff, but the forcing function of needing to be able to drive your critical path at will in my experience leads to better outcomes.

Re:Things you can’t do in Rust (and what to do instead) by tialaramex on Saturday May 15, 2021 @12:02PM (#27166370)
Composability bites you badly here. You need that ASAN run, with full coverage, for the entire C++ system, any time any part of it changes, even if the changed element seems irrelevant and clearly safe, the way C++ is defined that doesn't mean it didn't make the whole system unsafe.

But since Rust's Memory Safety guarantees apply to components, the composition of those components also has Memory Safety by definition.

If you have one guy writing incredibly scary to-the-metal unsafe Rust to squeeze out 1% more performance from a system that's costing 85% of your company's burn rate, you can put that tiny component through ASAN hell, looking for any possible cracks in its Memory Safety with all sorts of crazy input states.

But the sixteen other people in the team writing stuff like yet-another REST JSON handler entirely in Safe Rust don't need that effort and when you compose all these pieces together to build the actual product, you don't need ASAN again, you checked that the scary bit was safe and you're done.

Re:Things you can’t do in Rust (and what to do instead) by dhosek on Saturday May 15, 2021 @11:03PM (#27170858)
Oh God, CMake and dependencies are at least 80% of why I decided to learn Rust. I decided to give a shot to C++ back in November/December for a project I'm working on and it was ridiculously painful to do something like set up a simple library with unit tests using CMake, especially coming from writing Java in my day job where it's trivial to do this sort of thing. Starting from scratch with Rust about a month and a half ago, I've been more productive in that month and a half than I was in five months of banging against CMake and trying to figure out how to bring in external dependencies.
Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Saturday May 15, 2021 @09:45AM (#27165170)
It's not that Rust catches these issues like a sanitizer or linter would, it's that they can't exist by design. The compiler is aware of potential type-, lifetime- and ownership safety issues, and you don't need to run any code to figure out if your code is memory safe or not; static analysis is enough.

Also, even if Rust only caught by itself what Clang and half a dozen analyzers would catch, you also get a really nice language as a bonus. There is much more to Rust than just safety.

Re:Things you can’t do in Rust (and what to do instead) by astrange on Saturday May 15, 2021 @10:13PM (#27170641)
> It's not that Rust catches these issues like a sanitizer or linter would, it's that they can't exist by design.

Not saying this is true about Rust, but I find these approaches dangerous because they can move bugs off to a different meta level where they're harder to detect.

For instance, some people make safe C dialects where signed integer overflow wraps around or variables are auto initialized to 0. Well, what if you didn't want to overflow at all or 0 was the wrong value? Now you can't find the bug because the program has been redefined to do the wrong thing instead of simply crashing.

Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Sunday May 16, 2021 @01:53AM (#27171512)
I get how those concerns would apply to a C dialect, but not really to Rust. Since Rust is an entirely new language you shouldn't expect it to work exactly like C, unlike you would expect of a C-derived language.

Most of Rust's safety features are handled at compile time, and they are usually handled explicitly, not implicitly. A few examples about initialization:

* An instance of a struct is created by giving an initial value to each field. Leaving out any field is a compile error. Since structs are always completely initialized, you can't accidentally pass references to partially initialized structs like you could in a C++ or Java constructor.

* All local variables must be initialized. Accessing a variable before initialization is a compile time error.

* Structs have no implicit default value. The default value can be defined by implementing a trait, either by yourself or by deriving it with a macro (which would default integers to 0 and so on). Default values are only used by a fixed set on functions in the standard library, and never implicitly.

The overflowing case is one of the only cases where Rust is a bit more implicit. Integer overflow is checked at run time in debug builds (so over/underflow causes a panic) and defined to wrap around in release builds. However, the standard library also defines methods on numbers which explicitly use wrapping, saturating or checked (either return a Result value or crash) semantics.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:51AM (#27165702)
So, I'm not really sure how the distinction between `rustc` and the government-issue `clang` chain really matters unless one is a lot faster, and they're both really slow.

The by-design thing I get for like something with a port open, but as a default? It's been a few months but the last time I was trying to hack a Rust project printing stuff out hit the borrow checker. I can live without that.

Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Saturday May 15, 2021 @11:03AM (#27165813)
You've mentioned the printing issue a couple of times in this thread, and it sounds pretty weird to me as a someone who has used Rust for a couple of years. Without knowing the specifics I can only assure you that if you know the basics of the language, you'll have no issues printing whatever you want whenever you want.

Rust is admittedly a language you can't just jump into without spending some time learning the fundamentals. If you try to do anything non-trivial without grokking the basics of ownership and borrowing you are bound to run into frustrating issues.

Re:Things you can’t do in Rust (and what to do instead) by db48x on Saturday May 15, 2021 @11:47AM (#27166248)
He probably tried to do dbg!(foo), which takes foo by ownership and consumes it. Doing dbg!(&foo) will accomplish the same thing (printing foo along with the line number and file name), but because it only uses a reference to the foo, it won’t consume the original. This is perfectly sound and logical once you know the explanation, but it is pretty weird to a newcomer.
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @12:33PM (#27166654)
The project was alacrity and my checkout is on a laptop I don’t have on hand at the moment so unfortunately I can’t gist my patch, but I’ll have that box tomorrow and I’ll try to remember to do so. I was attempting to use whatever all their other logging was using. ‘&’ was the first thing I tried because I’ve done the tutorials and then some, but after that got the borrow checker arguing about my new line of code as well as two others I didn’t touch, I rotated through all the other sigils brute force, IIRC it was a combination of commenting out another line and ‘’ that got me a log line. Now maybe that’s on alacrity because maybe they do ownership in a weird way. But even in Haskell, even as a novice on stackoverflow, ‘unsafePerformIO’ will get you a line printed to STDERR, and it’s not 50-80s to build 50-ish kloc every time.

I like learning programming languages, I like working on compilers, this stuff is basically my only hobby.

But as the TF2 people are learning the hard way, if a complete novice can’t get a log line in without understanding a bunch of novel context, PyTorch is taking your SO out to dinner pretty soon.

Now if Rust could build a million lines of code in 1-5s like it should be able to (and like it seems that e.g. Jai can) I wouldn’t care. I needed to get stuff done in C++ bad enough that I learned template metaprogramming, which I wouldn’t wish on an enemy. If Rust made my builds 50-100x faster in low optimization settings, I’d write it on clay tablets.

But what I actually get is a comparably slow build, a comparably “!$&@>>>>”-heavy syntax, yet another failure to do macros that impress a Lisper in a curly brace language, and now the static analyzer’s usually good advice is mandatory and can’t be turned off to do a quick experiment.

I always have to watch my cynicism because I’m a bit autistic and I offend way more often than I mean to, but if I’ve got 1MM lines of C++, I’ve got a pain in the ass on my hands. If I start porting any meaningful part of that over to Rust, now I’ve got two giant pains in the ass.

Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Saturday May 15, 2021 @01:30PM (#27167158)
Initial builds are indeed quite slow, especially when a project has a lot of dependencies. However, in most cases further builds are not that bad. I have never built Alacritty from source so I don't really know if there are any specific issues with it, but from my experience incremental builds take just a few seconds in medium sized projects.

Additionally during development a full build is usually not necessary all the time; oftentimes it's just enough to check the code for errors with `cargo check`, which is usually significantly quicker than building a full debug binary.

Edit:

I tested building Alacritty from source on my computer (Ryzen 5600X, Windows 10). The initial build (consisting of 130 crates) took 34 seconds. Building again after adding a single print statement took 6 seconds, and `cargo check` took about half at 3 seconds. It's not ideal by any means, but IMO it's not also unreasonable for 25K lines of code, plus those ~130 dependencies.

Re:Things you can’t do in Rust (and what to do instead) by MaxBarraclough on Saturday May 15, 2021 @09:51AM (#27165231)
What you've described is a way of catching some memory-safety problems in C++ codebases. There's no easy way to catch them all. Even Chromium is riddled with memory-safety issues that result in serious security vulnerabilities. [0][1] We don't have a practical way of writing large and complex C++ codebases that are entirely free of memory-safety issues.

I don't know enough about Rust to comment on whether it does a better job than C++ on reference cycles, but my suspicion is that it does.

[0] https://www.chromium.org/Home/chromium-security/memory-safet...

[1] Related discussion: https://news.ycombinator.com/item?id=26861273

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:47AM (#27165666)
Chromium is a *way* legacy codebase, I think WebKit goes back to like Konqueror or something? Chromium is a very weird example to cite for modern C++ vs. modern Rust memory safety.

AFAIK avionics software is still largely written in Ada, because it won't let you fuck up meters vs feet type stuff. And if someone said: "Rust has a slam-dunk niche: we're going to crank static analysis past helpful to downright intrusive because sshd simply can't buffer overflow", I'd be like, yeah, ok.

But at the time I stopped using it, Alacritty couldn't handle meta keys on Big Sur, and I wanted to fix that, so I spent a weekend or two that I really couldn't spare trying to unfuck it, but between `print` not being obvious (because someone had already borrowed the thing I wanted to print out) and the build being slower than C++ I timed out.

Re:Things you can’t do in Rust (and what to do instead) by cvwright on Saturday May 15, 2021 @11:17AM (#27165969)
OTOH Chrome has one of the best teams in the world working on it, funded by one of the richest companies in the world, with the best tools. And they take security very seriously.

If they can’t get it right, who can?

Re:Things you can’t do in Rust (and what to do instead) by MaxBarraclough on Saturday May 15, 2021 @12:52PM (#27166820)
A good point, but I imagine benreesman's counterpoint would be that things might be different if Chromium were written entirely in modern C++, strictly following modern best practices.

My suspicion is that this is too optimistic, but I can't really substantiate it.

What would be a good security-sensitive modern C++ codebase, ideally from a high-profile source like Google, to compare against?

Re:Things you can’t do in Rust (and what to do instead) by astrange on Saturday May 15, 2021 @10:14PM (#27170646)
Doesn't the definition of modern C++ change every few years? This might not be possible if any such project takes more than two years to write.
Re:Things you can’t do in Rust (and what to do instead) by imtringued on Saturday May 15, 2021 @10:01AM (#27165318)
Isn't that a complete drag? Needing to install a dozen different tools just to do something basic as maintain security? There is no way you can hold every C++ project up to this standard. If you asked me to write software in C++ I would forget to use half the tools you listed and your list isn't even complete to begin with!

Of course this is not an answer to your comment.

Even if you use std::unique_ptr you can still run into use after free bugs. std::unique_ptr is just heap allocation with a "stack allocation style" lifetime. You can still run into use after free by putting a reference to stack allocated data (this applies to std::unique_ptr as well) into a struct or global variable that outlives the stack allocated data. std::unique_ptr isn't really meant to solve use after free, it exists to ensure that heap allocated data is properly freed eventually. It saves you the discipline to match every new with a free but nothing more.

This is something that you can only solve with a borrow checker. If you were to add the ability to detect these types of problems in C++ then you would have essentially added a borrow checker to C++.

Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Saturday May 15, 2021 @04:04PM (#27168489)
ASan, UBSan, etc. are absolutely life-changing, no doubt about it. But there's a pretty big difference between catching things statically, and catching them at runtime. If you have an issue that, say, only triggers on odd-numbered Tuesdays on Windows 7, your tests suite is probably going to miss it, and ASan isn't going to be able to help you.

Here's an example from one of Herb Sutter's talks, which I refer to frequently. He describes an issue that can come up with shared_ptr in reentrant/callbacky code, and the punchline is that you have to be careful never to dereference a shared_ptr that might be aliased: https://youtu.be/xnqTKD8uD64?t=1380

I also just wrote a giant example of my own :) in reply to your toplevel comment. https://news.ycombinator.com/item?id=27168368. TSan will be pretty good at catching some of the simple variants of this, like where you totally forget to take a lock. But it's going to have a hard time with cases where you "stash" a reference longer than you should, because later uses of the reference might appear safe for a while yet become unsafe down the road with unrelated code or timing changes.

Another issue with ASan and UBSan, is that every application has to run them (and maintain its own test suite comprehensive enough to make them useful). With static checks, a memory-safe library is memory-safe for everyone, even for applications that aren't particularly careful with their tests. The library author is able to express their safety requirements through the language, and all callers have to respect those requirements all the time.

Re:Things you can’t do in Rust (and what to do instead) by andrewaylett on Saturday May 15, 2021 @01:46PM (#27167309)
This stack would catch _most_ problems, but not necessarily at compile time. It's unsound, because it's still possible to write data races. And it's possible that two components, each on their own correct, combine to make something that isn't correct.

Rust's borrow checker makes it impossible to write code containing a data race. It does this by only accepting a subset of possible safe programs, but this is (or at least may be) a reasonable trade-off due to the guarantee you get.

It's not that you can't write safe code in C++, but you're always at the mercy of your validation to try to have confidence that you've actually managed to do what you set out to do. While Rust obviously doesn't preclude bugs at all, but it does enforce that you _can't_ write a certain class of previously-prevalent bugs.

I think this blog post from Mozilla does a good job of what that means in practice: https://blog.rust-lang.org/2017/11/14/Fearless-Concurrency-I...

Re:Things you can’t do in Rust (and what to do instead) by jandrewrogers on Saturday May 15, 2021 @02:25PM (#27167624)
> It does this by only accepting a subset of possible safe programs, but this is (or at least may be) a reasonable trade-off due to the guarantee you get.

I think this is correct but would expand on the nature of the tradeoff. Rust only accepts a subset of safe programs, and can express any program in the abstract, but that subset may not contain the optimal safe program. In some cases, differences in practical performance between the expressible safe program and the optimal safe program can be quite large.

Modern C++ cuts a tradeoff along a different dimension: it will accept unsafe rubbish but the optimal safe program is also expressible in virtually all cases. C++ has large niches where it can express optimal safe programs, and where this optimality is important, that Rust cannot. Obviously it is incumbent on the programmer to write safe code in C++, but the flexible type system is more capable of enforcing safety than I think people expect, particularly in recent versions of C++.

Re:Things you can’t do in Rust (and what to do instead) by andrewaylett on Monday May 17, 2021 @07:53AM (#27182434)
Agreed.

But there's optimal and there's "optimal" -- by restricting the developer, we open up more opportunities for the compiler to optimise the code (for all that Rust isn't necessarily able to take advantage of these opportunities yet) and a judicious use of `unsafe` may even help us to build an abstraction that gives us the optimal program anyway. Crucially, code that uses unsafe is still no less safe than ordinary C++ code.

From my days as a compiler engineer, I definitely prefer to write clear code and fix the compiler rather than try to convince the compiler to produce the right result by mangling code. And to build my control logic as an abstraction, even if it's only going to be used in one place, so it can be verified separately from the business logic it drives.

Re:Things you can’t do in Rust (and what to do instead) by sk1459 on Saturday May 15, 2021 @08:46PM (#27170265)
>impossible to write code containing a data race

https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Rust+data+r...

Re:Things you can’t do in Rust (and what to do instead) by andrewaylett on Monday May 17, 2021 @07:42AM (#27182362)
OK, I'll grant I should have added scare quotes to "impossible".

A quick check suggests that (as would be expected) they're caused by `unsafe` blocks. Specifically, by the developer claiming that a value was safe to send to a different thread while it actually wasn't. One thing to note is that these bugs neutralised the compiler's validation is these specific cases -- allowing, rather than causing, races. Using unsafe means the developer needs to ensure they maintain the invariants themselves within the unsafe block, while in C++ one has to maintain these invariants in _all_ code.

Re:Things you can’t do in Rust (and what to do instead) by fnord123 on Saturday May 15, 2021 @09:53AM (#27165247)
Cool that you use all those tools. Wouldn't it be cool to be able to depend on libraries knowing they all use those settings? And you can depend on libraries by putting a single line in a toml file.

I mean C++ dependency management is so bad there is a concept of a header only library so you just have to copy the file into your project with no support for managing versions.

C++ dependency management is so bad people use the OS installed dependcies because they struggle to set up a build environment otherwise.

What I'm saying is that C++ is pretty good and toe to toe C++ with all the tools you describe and Rust are fairly comparable. But with Rust the whole ecosystem uses it so the network effects make things much better. And it's snowballing.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:20AM (#27165462)
You make a really good point about C++ headers. Textual inclusion of globs of bytes into translation units is 1970s legacy stuff that totally fucks up reasonable build times, and for all the talk about C++20 modules they haven't delivered yet.

I actually think this is one of the things that Rust could crush C++ on, because build times are becoming the whole show on big C++ projects.

It's super weird to me that C++, with this whacky 1970s constraint that totally fucks up modularity, still builds neck-and-neck or better with Rust.

In principle Rust could do *way* better on this, and that is a feature that might get me to consider Rust seriously, no matter how stupid I think the borrow checker is. But Rust still compiles dog slow...

Re:Things you can’t do in Rust (and what to do instead) by fnord123 on Saturday May 15, 2021 @03:58PM (#27168445)
>It's super weird to me that C++, with this whacky 1970s constraint that totally fucks up modularity, still builds neck-and-neck or better with Rust.

Not so fast! The compilation and linking is neck and neck with Rust so you can have an ELF in the same amount of time. But then you have to run all the C++ tools you mentioned to have parity with what the Rust compiler is doing.

> for all the talk about C++20 modules they haven't delivered yet.

Even when they're delivered, will all the libraries you depend on use them?

>In principle Rust could do way better on this, and that is a feature that might get me to consider Rust seriously, no matter how stupid I think the borrow checker is. But Rust still compiles dog slow...

The team that built the Borrow Checker deserves the Turing Award. It is an outstanding bit of computer science and engineering. I'm surprised that you think it's stupid.

It used to be dog slow but it's gotten very fast in the past two years. Another achievement.

>In principle Rust could do way better on this, and that is a feature that might get me to consider Rust seriously

Modules? Your take away from all this is that modules are the killer feature of Rust and that the Borrow Checker is stupid?

I call shenanigans. You are an elaborate troll. Well done for getting two responses out of me.

Re:Things you can’t do in Rust (and what to do instead) by conradludgate on Saturday May 15, 2021 @12:01PM (#27166367)
I find if you're aware about how you define your modules, incremental compiles are usually pretty quick. Yes a complete build can take a while but tools like sccache[0] can help with that in CI pipelines and when getting a new dev environment up.

[0]: https://github.com/mozilla/sccache

Re:Things you can’t do in Rust (and what to do instead) by galangalalgol on Saturday May 15, 2021 @11:04AM (#27165819)
I have the opposite problem with rust dependency management, its too easy so you get deep widely branching dependency trees by differing authors with differing licenses. From a corporate use perspective this is a legal nightmare. From a security standpoint, this is a trust nightmare.
Re:Things you can’t do in Rust (and what to do instead) by Keyframe on Saturday May 15, 2021 @11:18AM (#27165980)
For licenses there's cargo-deny https://github.com/EmbarkStudios/cargo-deny

On the security standpoint and a wide net of crates.. that's a problem, same as with npm/yarn/pip/whatever and I agree on that. That one bugs me as well. Difficult to audit.

Re:Things you can’t do in Rust (and what to do instead) by galangalalgol on Saturday May 15, 2021 @11:23AM (#27166006)
Cargo-deny is accurate, but it accepts no legal or financial risk if it was in some case wrong and you infected a codebase with gplv3, and thus corporate lawyers everywhere ignore it.

Edit: this post keeps getting up and down voted. I suspects it has to do with the phrase infected by gplv3. I like the license fine, but being realistic many businesses treat it like radioactive waste, so that has to be a consideration

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:14AM (#27165937)
In fairness, you have those problems no matter how you include other people's code. At least Cargo as far as I'm aware uses a SAT-solver to deliver you a working dep graph unlike `pip` or `npm` or any of that nonesense. (as long as I remember correctly that Carl Lerche wrote that part. Sidebar: wicked smart guy).
Re:Things you can’t do in Rust (and what to do instead) by galangalalgol on Saturday May 15, 2021 @11:21AM (#27165998)
You do, but clunky dependency management meant fewer less granular dependencies.
Re:Things you can’t do in Rust (and what to do instead) by fluffything on Saturday May 15, 2021 @09:37AM (#27165095)
Does that warn if you do:

vector<int> v{1,2,3,4}; for (auto&& i: v) v.push_back(i);

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:02AM (#27165331)
In my little toy build I set up no, it doesn't warn me that smashing a data structure while iterating over it at the same time gives UB. I'm 50/50 on if there's a flag for that, don't actually know.

Again, in the spirit of becoming more educated, what's the equivalent Rust code? I have `rustc`/`rustup` on my box so I can run that too.

Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Saturday May 15, 2021 @10:11AM (#27165392)
This should be about equivalent. It does not compile, as expected. https://play.rust-lang.org/?version=stable&mode=debug&editio...
Re:Things you can’t do in Rust (and what to do instead) by gravypod on Saturday May 15, 2021 @10:18AM (#27165442)
Another fun feature of rustc is you can execute this command: rustc --explain E0502

It gives you a small example of what the error is, explains it, and tells you how to fix it.

This is a very nice feature for new people (like myself).

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:40AM (#27165618)
That's definitely useful, and I'm not completely mystified by the notion that simultaneous borrowing of something as both mutable and immutable is something that Rust watches for.

In C++ you (usually) do this with `const`, which is fairly low friction, very statically analyzable, and I'm a little unclear what bug hardcore borrow-checker static stops me or my colleagues from making that `const` can't catch?

Re:Things you can’t do in Rust (and what to do instead) by adwn on Saturday May 15, 2021 @11:06AM (#27165850)
> In C++ you (usually) do this with `const`, which is fairly low friction, very statically analyzable, and I'm a little unclear what bug hardcore borrow-checker static stops me or my colleagues from making that `const` can't catch?

Rust catches the bug where you forget to use `const`, because the C++ compiler doesn't force you to use it. Your argument boils down to "I don't need Rust's borrow checker, I just have to remember to use a dozen tricks, follow various patterns and guidelines, run several static analyzers and runtime checks, and I'm almost there".

This is not meant as an attack against you. I used to program in C++, and I'm mostly using Rust now. The borrow checker frees up those brain resources which had to keep all those tricks, patterns, and guidelines in mind.

Re:Things you can’t do in Rust (and what to do instead) by whb07 on Saturday May 15, 2021 @11:33AM (#27166112)
Here’s a simple point for you to consider. Let’s assume you and your team are 10x devs with perfect knowledge and use all the right tools. What happens when you guys leave or someone who isn’t up to your standard contributes, or is a junior dev?

Imagine all the best tools and all the best and memory safe features all rolled up to one called Rust.

Lastly, with C++ there are many situations where the memory unsafe actions are not caught until they are triggered dynamically. So like others have mentioned, you’d have to have the best test suite combined with the best of fuzzing etc.

Or you can just use Rust where nearly everything is caught at compile time with useful errors and when something funky does happen at runtime it will just panic before you cross into UB/ unsafe land

Re:Things you can’t do in Rust (and what to do instead) by reecko on Sunday May 16, 2021 @12:32AM (#27171251)
It is a pity that none of the replies to this comment has actually clarified your doubts...

Assuming the absence of `const_cast`, C++'s `const` ensures that a data of the particular type doesn't get modified. That's it. Rust on the other hand, tracks and restricts aliasing. This means you can't get both a constant and non-constant reference to an object or anything owned by it (more precisely anything transitively reachable from it). This is helpful in preventing issues with invalid pointers (like iterator invalidation). For instance, if you have already borrowed an iterator (which is essentially a reference) you can't issue mutable operations on the vector (issuing mutable operations entails a mutable borrow), and that could potentially reallocate the backing memory of the vector. This property is also useful for preventing multiple writes to the same location in a multi-threaded application, making programs adhere to the single-writer principle by-construction.

The downsides are that you might sometimes need to contort your code or your program architecture or perform mental/type gymnastics to write some trivially safe code or even use unsafe (or else lose performance) to satisfy the borrow checker.

Re:Things you can’t do in Rust (and what to do instead) by burntsushi on Saturday May 15, 2021 @09:50PM (#27170546)
I've read your comments in this thread, and with all due respect, I think what you're missing is a very simple truth: Rust is safe by default. C++ is not. This is Rust's core value proposition. It is precisely the thing that permits AND encourages designing safe abstractions even if it internally uses `unsafe`. Rust's value is in allowing you to compose safe code without fear.

If this doesn't seem like a game changer to you, then you probably don't grok its scope and impact. I don't really know how to give that to you either in HN comments. I think you maybe need a synchronous dialogue with someone.

Re:Things you can’t do in Rust (and what to do instead) by electrograv on Saturday May 15, 2021 @11:11AM (#27165910)
Const in C++ is entirely unlike immutability in Rust. Even ignoring the existence of “const_cast”, C++ const is vastly weaker than Rust immutability in several extremely fundamental ways that should be immediately obvious if you’re a C++ professional with even a surface level introductory understanding of Rust. At this point you honestly should just take some time to learn a bit of Rust, and it will likely all make sense. If not, it’s possible you’re relatively amateur C++ developer (no shame in that) lacking experience of the many ways in which C++ const falls very short.

But to directly answer your question, suppose I have a “struct FloatArrayView { float* data; size_t size; };” Of course this is a toy example, but humor me for now and consider the following:

1. Without excessive custom effort (e.g. without manually unwrapping/wrapping the internal pointer), how do I pass it to a function in C++ such that the data pointer within becomes const from the perspective of that function (i.e. you’ll get a compile error if you try to write to it?) Hint: It’s very complex to do this in C++, vs trivially easy in Rust. And no, passing as const or const reference to “FloatArrayView” does NOT work. The only solution in C++ for complex composite types operating with “by-reference semantics” is ugly, complex, and horribly error prone to maintain correctly. For a more concrete example, consider how “unique_ptr” works with the constness of the value it holds. A “const unique_ptr<T>” is NOT a unique pointer to const T. A “unique_ptr<const T>” is, but the relationship and safe conversions between these are not simple or easy to implement or even use in many cases. It gets even worse when you need to implement a “reference semantics” type like this that is inappropriate to be a templated type, or contains a variety of internal references unrelated to the template arguments.

2. Now suppose I solve #1 and pass this into some class method, which then stores a copy of the const reference for later. But I as the caller have no way of knowing this. So after that method returns, I later proceed to modify the data via my non-const reference (which is a completely valid operation), but this violates the previous method’s assumption that the data was immutable (will never change). This creates an incredibly dangerous situation where later reads from that stored const reference to data (that was assumed to be immutable) is actually going to actually yield unpredictably changing results. Const is not immutable. Question: How do you make it so C++ guarantees that passed reference is truly immutable and will never be mutated so long as the reference exists, and enforce this guarantee at compile time? In Rust this is easy (in fact, it’s the default). In C++, it is impossible. The closest you can get in C++ are runtime checks, but that’s nowhere near as good as compile time checks.

Edit: Removed a bunch of perhaps unnecessary extra C++ trivia which I’ll save for later :)

Re:Things you can’t do in Rust (and what to do instead) by reecko on Sunday May 16, 2021 @01:15AM (#27171393)
This is actually funny because unlike C++, Rust doesn't have true immutable types. Instead Rust restricts mutability in two ways. One is immutable bindings, and the other is the shared references. Your `unique_ptr` is example is how it ought to work actually. That way you have the ability to parameterize by mutability which Rust cannot.

To be more clear, in Rust, the `mut` you see in bindings (like `let mut blah = ...`) is wildly different from the `mut` in `&mut T`. There was discussion on whether the latter should be renamed to `uniq` (because `mut` is misleading). In any event, Rust lacks `const` types. There is no `const T` like in C++. So something like this is impossible,

  std::vector<const int> vec;
You can't have just the elements of a collection to be immutable like the above example in Rust.

Secondly, a value of a type `&T` can be mutated internally (aka interior mutability). A function taking a `&T` type and mutating it behind the scenes is very whacky. AFAII, interior mutability exists only to trick the borrow checker using the `*Cell` types (which use unsafe internally BTW).

Re:Things you can’t do in Rust (and what to do instead) by jcelerier on Saturday May 15, 2021 @03:03PM (#27167926)
How would one make e.g. in Rust then ?

   #include <vector>
   int main()
   {
     std::vector<int> foo{1,2,3,4,5};
     foo.reserve(foo.size()* 2);
     for(auto it = foo.begin(), end = foo.end(); it < end; ++it)
       foo.push_back(*it);
   }
Re:Things you can’t do in Rust (and what to do instead) by paavohtl on Saturday May 15, 2021 @03:33PM (#27168170)
There are a couple of options:

- Repeating the vector using the built-in method `Vec::repeat`. This allocates a new vector, but `reserve` is likely to do the same, just implicitly.

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

- Using a traditional for loop. There are no lifetime issues, because a new reference is acquired on each iteration. The reserve is not required, but I included it to match your C++ version. https://play.rust-lang.org/?version=stable&mode=debug&editio...

- Creating an array of slices and then concatenating them into a new Vec using the concat method on slices: https://play.rust-lang.org/?version=stable&mode=debug&editio...

Re:Things you can’t do in Rust (and what to do instead) by Lev1a on Saturday May 15, 2021 @03:27PM (#27168116)
The most short and elegant example I could come up with that actually worked (since the example above really shouldn't work in Rust in the first place):

    fn main() {
        let mut v = vec![1, 2, 3, 4, 5];
        let new_size = v.len()*2;
        v = v.into_iter().cycle().take(new_size).collect();
    
        println!("{:?}", v);
    }
https://play.rust-lang.org/?version=stable&mode=debug&editio...
Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Saturday May 15, 2021 @04:43PM (#27168829)
Other comments have answered this specific question, and I think it might be interesting to look at a similar-looking question that's actually more problematic for Rust. What I'll ask is, what's the Rust equivalent of this:

    #include <vector>

    void do_stuff(int &a, int &b) {
      // stuff
    }

    int main() {
      int my_array[2] = {42, 99};
      do_stuff(my_array[0], my_array[1]);
    }
That is, how do we take two non-aliasing mutable references into the same array/vector/view/span at the same time. (To be clear, none of the following applies to shared/const references. Those are allowed to alias, and this example will just work.) Notably, the direct translation doesn't compile:

    fn main() {
        let mut my_array = [42, 99];
        do_stuff(&mut my_array[0], &mut my_array[1]);
    }
Here's the error:

    error[E0499]: cannot borrow `my_array[_]` as mutable more than once at a time
     --> src/main.rs:7:32
      |                                                                 
    7 |     do_stuff(&mut my_array[0], &mut my_array[1]);
      |     -------- ----------------  ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
      |     |        |
      |     |        first mutable borrow occurs here
      |     first borrow later used by call
      |
      = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
The issue here is partly that the compiler doesn't understand how indexing works. If it understood that my_array[0] and my_array[1] were disjoint objects, it could maybe deduce that this code was legal. But then the same error would come up again if one of the indexes was non-const, so adding compiler smarts here wouldn't help the general case.

Getting multiple mutable references into a single container is tricky in Rust, because you (usually) have to statically guarantee that they don't alias, and how to do that depends on what container you're using. The suggestion in the error message is correct here, and `split_at_mut` is one of our options. Using it would look like this:

    fn main() {
        let mut my_array = [42, 99];
        let (first_slice, second_slice) = my_array.split_at_mut(1);
        do_stuff(&mut first_slice[0], &mut second_slice[0]);
    }
However, other containers like HashMap don't have `split_at_mut`, and taking two mutable references into e.g. a `HashMap<i32, i32>` would require a different approach. Refactoring our code to hold i32 keys instead of references would be the best option in that case, though it might mean paying for extra lookups. If we couldn't do that, we might have to resort to `Rc<RefCell<i32>>` or trickery with iterators. (This comment is too long already, and I'll spare the gory details.)

At a high level, Rust's attitude towards multiple-mutable-references situations is leaning in the direction of "don't do that". There are definitely ways to do it (assuming what you're doing is in fact sound, and you're not actually trying to break the aliasing rule), but many of those ways are advanced and/or not-zero-cost, and in extremis it can require unsafe code. Life in Rust is a lot easier when you refactor things to avoid needing to do this, for example with an entity-component-system sort of architecture.

Re:Things you can’t do in Rust (and what to do instead) by devit on Saturday May 15, 2021 @05:17PM (#27169113)
Use a crate that provides safe functions implemented with unsafe code to do that, like https://docs.rs/splitmut/0.2.1/splitmut/
Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Saturday May 15, 2021 @06:43PM (#27169654)
Neat! I bet we could add a macro to that crate to make it work with any (static) number of references. A variant of this using a HashSet to check arbitrary collections of keys might be cool too.
Re:Things you can’t do in Rust (and what to do instead) by namibj on Saturday May 15, 2021 @10:15AM (#27165428)
let mut v = vec![1,2,3,4]; for i in v.iter() { v.push(i);};

And that doesn't work, because the v.iter() is sugar for Vec::iter(&v), while the v.push(i) is sugar for Vec::push(&mut v, i) . I think it'd use deref coercion on the i, as Vec::iter(&v) gives you `i: &isize`. If this wasn't ints (or other `Copy` types, for that matter), you'd need to use .into_iter() to consume the Vec and get ownership of the entries while iterating, or use `.push(i.clone())` because `Vec<T>::push(&mut self, T)` is the signature, and you can only go automatically from `&T` to `T` for `Copy` types. Actually, it _may_ even need `v.push(*i)`, thinking about it. Try on https://play.rust-lang.org

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:32AM (#27165561)
So I don't have the same intuition for desugaring `vec!` that I do for desugaring `for (auto&& blah : blarg)`, but in either case if you desugar it the problem becomes a lot more clear. The Rust borrow checker errors I'm sure become second nature just like the C++ template instantiation ones do, but that is faint praise. To get some inscrutable C++ template instantiation error you have to mess with templates, and that's for people who know what they're doing. In Rust it seems like the borrow checker isn't for pros, it's C++-template complexity that you need to get basic shit done.

C++ is actually a pretty gradually-typed language, and I'm in general a fan of gradual typing. I don't mind that some people prefer BDSM-style typing, but IMHO that goes with GC e.g. Haskell a lot better than it does with trying to print something out or copy it or whatever.

Re:Things you can’t do in Rust (and what to do instead) by zxzax on Saturday May 15, 2021 @02:44PM (#27167796)
It's not the same as C++ template errors. This is something that will directly cause a segfault in your code, that the Rust compiler is able to catch; AFAIK no C++ compiler would be able to catch that.
Re:Things you can’t do in Rust (and what to do instead) by kd5bjo on Sunday May 16, 2021 @02:27AM (#27171652)
The problem here is that you’re trying to iterate over `v` and modify it at the same time. The usual fix is to first decide the changes that should be made, and then apply them after the loop:

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

Alternatively, you can loop over indices instead of values, which doesn’t require the loop to maintain a reference to `v` across iterations:

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

Re:Things you can’t do in Rust (and what to do instead) by Too on Sunday May 16, 2021 @01:35AM (#27171450)
Everything owned by unique_ptr is not realistic, some times you need shared state. Rust provides a safer alternative to references if you don't want to go all shared_ptr. Even Rc becomes better than shared_ptr due to single mutating owner limit, especially for multithreading. Even with clang-tidy turned to 11 there are still many other UB-landmines lurking not only related to memory ownership and you'd be fighting the compiler even more over contradicting requirements or opinions.

All the tooling you've just listed adds build complexity, on top of a build system that is already an abomination of makefiles, CMakeLists and lack of package manager. Let's not forget all the header files duplicating half of your implementation.

Re:Things you can’t do in Rust (and what to do instead) by divs1210 on Saturday May 15, 2021 @09:38AM (#27165105)
just code in assembly then.

Batteries included with safe defaults is a BIG feature.

Legacy C/C++ code is littered with so many memory related bugs that big companies are funding people to rewrite essential unix utils in Rust.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:13AM (#27165410)
No argument that legacy C/C++ code is Swiss cheese on 1980s memory bugs in a lot of cases.

Modern C++ vs. modern Rust. Why is modern Rust better? Legacy C++ can be transformed into modern C++ is a semi-mechanical, semi-you-emply-someone-good-at-emacs way, at a cost in time, money, and risk way less than empty editor.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:17AM (#27165967)
For a post that started with "Rant Disclaimer", this has generated kilobytes of useful, insightful responses, and I'm going to be looking for spare time everywhere I can find it to follow up on all the great resources. I do intend to reply to everyone's comments, but the 20 of you are outrunning the 1 of me on that. If it takes me a few hours to reply thoughtfully to your thoughtful replies please bear with me.
Re:Things you can’t do in Rust (and what to do instead) by steveklabnik on Saturday May 15, 2021 @01:35PM (#27167216)
While some people complain about the Rust community being evangelical, you'll find this is common. We've built a culture of helping answer questions, sometimes to the point of being too enthusiastic about it. If you ever need help, jumping into the forums or various chat platforms will usually get you a courteous answer in minutes.

We aren't perfect, but this is one of the aspects of the Rust community I'm most proud of.

Re:Things you can’t do in Rust (and what to do instead) by stouset on Saturday May 15, 2021 @06:07PM (#27169460)
To be completely honest, I think you’ve had a bigger impact than most in making the community that way.

You were a huge boon to the Ruby/Rails community, and you’ve taken that experience and been instrumental in building a helpful, enthusiastic, and friendly community around Rust. One of these days I hope our paths cross so I can buy you a drink.

Re:Things you can’t do in Rust (and what to do instead) by steveklabnik on Saturday May 15, 2021 @08:21PM (#27170157)
Aw shucks, thank you! That’d be great. Someday!
Re:Things you can’t do in Rust (and what to do instead) by atoav on Saturday May 15, 2021 @11:16AM (#27165965)
I had an awful time when I started using Rust because I had a strong (object oriented) view of how to structure my code. At one point where nothing seemed to work and I didn't manage to get anything to compile I just was like: "ok, I give up Rust, I will do it your way".

From then on everything worked surprisingly easy.

The 3 main things that make Rust great (besides thenusual selling points) are IMO:

- the library manager/dependency managment is great

- Even if you are never gonna use Rust again, some of the lessons you have to learn when learning Rust are universally useful. Thinking about ownership and race conditions the Rust way will certainly help you tackle some parricularily hard issues with multithreaded code in other languages as well.

- The amount of things you can rake as a given within Rust code is very high. If it compiles it usually works. If it doesn't it gives helpful indications why. These indications help you to understand your code better.

Re:Things you can’t do in Rust (and what to do instead) by giantandroids on Saturday May 15, 2021 @02:52PM (#27167851)
After years of dynamically typed / interpreted languages, I decided I wanted to learn a statically typed language and so I to set out to trial both Go and Rust. Rust was a painful experience. I kept trying to pass around simple types and constantly hit compiler failures.

I then set up Go and got started. Fell in love with it, I was immediately 10x more productive then I was with rust. I also found reading other people's code far more easier as well, where rust would have all this (for me) difficult syntax.

I want to like rust, but I honestly don't think I am smart enough.

Re:Things you can’t do in Rust (and what to do instead) by atoav on Sunday May 16, 2021 @04:25AM (#27172133)
The thing for me was: I realized the type system is not something to fight with, but something that you can utilize to always have certain guarantuees about what is going on, which can make it extremely easy to reason about code especially after your program reaches a certain size.

But to profit from this you have to reach a level where you are beyond fighting with the ownership model and with data types.

For small/quick scripting stuff I still go to python, because some problems can just be solved faster with it. I don't think there is anything wrong with that. It really depends on the scale of programs and the needed reliability IMO.

Re:Things you can’t do in Rust (and what to do instead) by giantandroids on Sunday May 16, 2021 @12:48PM (#27174936)
Thanks, I don't know that I am fighting it, its more that I just can't figure it out. Maybe I need to try again. I read the rust book last time, but large parts of it went over my head.
Re:Things you can’t do in Rust (and what to do instead) by lalaithion on Saturday May 15, 2021 @06:08PM (#27169461)
Coming from dynamically typed high level languages, you're learning two things at the same time when you're learning rust:

1) Low level programming 2) Typed programming

Both of which are difficult.

I would suggest learning one of Haskell or Scala and one of C or C++ first, and then trying Rust again.

Re:Things you can’t do in Rust (and what to do instead) by giantandroids on Sunday May 16, 2021 @12:40PM (#27174867)
As I said, I am getting on great with go now.
Re:Things you can’t do in Rust (and what to do instead) by stouset on Saturday May 15, 2021 @06:14PM (#27169506)
Rust is sometimes a painful experience because it forces you to deal upfront with an important concept other languages play fast and loose with.

You can absolutely get productive more quickly in other languages as a result. But to me, developers who take the time to get over that hurdle by and large become dramatically more productive in the long run, and that’s before you take into account the fact that their code will have near-optimal performance and be virtually bulletproof.

There’s a reason we’re regularly seeing best-in-class general purpose tools and libraries coming out of the Rust ecosystem.

Re:Things you can’t do in Rust (and what to do instead) by jkarneges on Saturday May 15, 2021 @01:25PM (#27167105)
You basically describe me. I've been doing C/C++ for like 20 years and usually for the right reasons (game dev, voip, embedded, desktop apps, proxy servers). When C++ is not needed, I choose Python.

I am super impressed by Rust. As of about a year ago I try to reach for it in any situation I would have otherwise reached for C++.

What stands out to me more than any particular feature is how competent the Rust creators are in designing for performance. The performance of C++ almost feels like an accident, because it was designed when computers were slower, and because for awhile it was the only game in town (even sloppy C++ often performs better than high-level languages). With Rust, performance is an ethos. It is very apparent from the language design and standard library design, that these people know what they are doing.

Re:Things you can’t do in Rust (and what to do instead) by da39a3ee on Saturday May 15, 2021 @09:45AM (#27165168)
> Where do I find the explanation of why Rust is less awful than C++ written by someone who has written a lot of C++ out of necessity,

The O’Reilly book by Jim Blandy and Jason Orendorff. It is a really fantastic book on a programming language, the best I’ve ever read. The new edition is due this year it seems.

https://www.oreilly.com/library/view/programming-rust-2nd/97...

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:21AM (#27165477)
Ordered. Thank you!
Re:Things you can’t do in Rust (and what to do instead) by unrealhoang on Saturday May 15, 2021 @11:41AM (#27166202)
Seconded, this book is so good in demonstrating Rust’s advantages as well as low level programming concepts with its beautiful visuals.
Re:Things you can’t do in Rust (and what to do instead) by ahartmetz on Saturday May 15, 2021 @11:46AM (#27166246)
Yeah, I also like it better than the official Rust book. My favorite programming language book is still K&R's C book, though.
Re:Things you can’t do in Rust (and what to do instead) by tialaramex on Saturday May 15, 2021 @12:38PM (#27166697)
K&R is excellent. One of the things that makes it stand out would be almost irrelevant today, it has an excellent hand-made index. If you're wondering about, say, arithmetic conversions, the index gets you straight to the page which lists exactly what you needed. Wondering when to pick enum over #define? Again, the index has your back.

Today online you've got full text search, maybe you find two, three hits that are irrelevant, but it's so cheap you barely care. And in a book today the index is probably auto-generated (hiring somebody to write an index is not a thing these days) and so it's almost useless with dozens of irrelevant entries, but hey, like I said, full text search, so who cares?

Because C is such a small language and it was essentially finished when the book was written, they get to do a pretty complete survey while also teaching you, so you read the book once, now you understand C pretty well. The Rust book is much better than C++ books I tried, but because Rust is still immature there are big sections that are being rewritten or have already been rewritten, and of course the whole book can't be reordered and started over each time, so overall it's uneven.

I am reluctant to buy a printed Rust book because of that immaturity. My (second edition) K&R is still a pretty good survey of the language. Are there things it doesn't cover? Yes. But few of them are fundamental, whereas I feel like if I bought a Rust book today, in five years it's a historical curiosity like my Stroustrup, except hopefully better written. I still consult my K&R a few times a year, I don't even know where the books I own on other languages (including the long obsolete Stroustrup) are, I might not have unpacked them after moving years ago.

Re:Things you can’t do in Rust (and what to do instead) by steveklabnik on Saturday May 15, 2021 @01:49PM (#27167333)
If you take a look at the Rust book from five years ago and today, it's actually 40 pages slimmer (540 pages for the first version, 500 for the second) because most of the examples for some more advanced features Just Work without needing those features explicitly, and some other things got simplified. None of that stuff is wrong, and is still useful at times, but is used less often.

The core feel of Rust is very much the same today as it was then. Just things got smoother overall. We'll see in ten more years.

(This is on my mind, as we'll eventually be releasing an updated book for Rust 2021, at some point. Probably early 2022. It will grow in size again, mostly due to adding stuff about async/await, which is a major new addition to the language, but only needed in certain circumstances.)

Re:Things you can’t do in Rust (and what to do instead) by k_bx on Saturday May 15, 2021 @09:41AM (#27165136)
My favourite three compared to years of Haskell experience are:

- runtime predictability. Our async high-load programs are already complex, and having a much more predictable runtime (no GC) makes things feel much more straightforward

- lack of bracket need. You get destructors from your types! No more async-exception or other accidental leaks

- no exceptions. The “?” syntax is truly genius, Holy Grail of Haskell error handling coming to life

Re:Things you can’t do in Rust (and what to do instead) by Glavnokoman on Saturday May 15, 2021 @09:24AM (#27164980)
Sounds like you might like Zig. It is not perfect either, but many things are done the proper way there. The only thing I really like about Rust it is that it tries to solve many problems at their roots. It failed in my opinion, but at least it tried to.
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @09:26AM (#27165000)
What’s the link that takes me down the Zig rabbit hole?
Re:Things you can’t do in Rust (and what to do instead) by matheusmoreira on Saturday May 15, 2021 @09:29AM (#27165021)
The Road to Zig presentation:

https://youtu.be/Gv2I7qTux7g

C but with the problems fixed.

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @09:34AM (#27165069)
Queued. Thank you!
Re:Things you can’t do in Rust (and what to do instead) by cletus on Saturday May 15, 2021 @11:16AM (#27165959)
So what I like about your comment is you’re clearly more pragmatist than zealot or ideologue.

So I don’t know Lisp or Haskell. I never learned in the college years when I might’ve had time and now I just don’t want to pay the years long learning curve. I’ve got shit to do.

But the big problem (for me) is I’ve completely turned off dynamic typing. Python did this to me and i I honestly don’t think I’ll ever go back. I refer to dynamic typing as “unit tests for spelling mistakes”. YMMV.

Another issue is I like simple grammars and relatively opinionated languages. I’m not the biggest fan of GC either. Years of tuning GC pauses of JVM have soured me on the boundless benefits of GC.

I give this as context to say that I like Go. You can learn Go in a really short amount of time. There’s usually only one way to do things in Go. That’s good. Less surprise and less arguments in teams.

An issue I have with C++ (and this applies to Lisp and Haskell too) is it allows people to be too clever for their own good. Look at 200 lines of Lisp and there might be a C compiler buried in there. Who knows? That might demonstrate the power of the language but is usually counterproductive to a team or project.

So memory safety is the big selling point of Rust. You need to buy into that and why things like static typing are good even though you might struggle with the type system and borrow checker at first.

Is better to fight the compiler than be surprised by the runtime (IMHO).

But Rust of course is not issue free and it differs from some long-standing and unfortunate design choices early in its life that are going to be hard to correct. Build times are a big one. See this [1] for more.

For the last few years I’ve written Hack (aka PHP) professionally. One thing one comes to really appreciate is cooperative async-await, which is pervasive. Writing C/C++/Java has taught me that of you every manually spawn a thread you’re going to have a bad time so you should do anything in your power to avoid this. Go is one flavor of alternative. Hack is another. I’m not sure I’ma big fan of Rust’s.

Ultimately, with Rust out any other language for that matter, you need to learn and buy into the idioms otherwise you’re going to have a bad time.

[1]: https://pingcap.com/blog/rust-compilation-model-calamity

Re:Things you can’t do in Rust (and what to do instead) by neilv on Saturday May 15, 2021 @07:36PM (#27169933)
I used to write a lot of C and C++ professionally, and have long thought that C is 100 times harder than is suggested by the apparent care taken writing much of the C code we've seen.

I've also done a lot of professional Lisp, since you asked. :)

I've only done a tiny bit of Rust thus far, and am not yet ready to say it's the holy grail of systems-y software development. But Rust has enough good and interesting ideas, and what now looks like a good community process for its evolution, and I've seen enough examples of people doing good work using Rust-- that I can imagine Rust turning out very well, and I'm willing to invest, and find out. (Ideally, at some point getting paid to do so, rather than with a slow trickle of weekend projects.)

I'll acknowledge a potential conflict of interest here. Compared to C, the difficulty of Rust seems much more immediate, and harder to fake, or to naively blow past. When you have to think and learn a lot just to get nontrivial code to compile, that seems like a higher barrier to entry for new practitioners. Which means, besides the usual tech industry dynamic of always getting new keywords on one's resume, and boosting the keywords that differentiate oneself... there's the aspect of Rust simply having a better competitive moat than, say, is had by yet another slightly different Web framework. That's not an attraction for me, I don't think, but it's difficult not to realize, when we're surrounded by that dynamic. I think there are better reasons to be interested in Rust, but I'll try to look out for, and be honest with myself about, potential conflicts of interest along the way.

Re:Things you can’t do in Rust (and what to do instead) by grok22 on Saturday May 15, 2021 @11:12AM (#27165918)
The column for the Rust language on this page (https://scattered-thoughts.net/writing/how-safe-is-zig/) with the rows of "compile time" for various memory issues is what is selling me on Rust that I am spending time with it hoping to sacrifice some difficult current learning time and some future tedious development and compile time to save on painful debug time for some kinds of issues. The problem is that the pay-off is at the end :-).
Re:Things you can’t do in Rust (and what to do instead) by the__alchemist on Saturday May 15, 2021 @10:27AM (#27165524)
For me, it's the overall experience. Ie: auto-generated docs for libraries, nice package manager, built-in linter and formatter, easy-to-install toolchain[s], high-level coding patterns etc.
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @11:11AM (#27165901)
That's a fair-sounding point. Java had this (but also a bunch of other problems).
Re:Things you can’t do in Rust (and what to do instead) by golergka on Saturday May 15, 2021 @09:47AM (#27165185)
Honest question: what views does one has to have to doesn't take non-browser JS seriously, and at the same time use Python? And what's unfortunate about node.js compared to it?
Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:09AM (#27165380)
Python has (more than one actually) trivially seamless FFI stories down to native (read: C++) code. I personally like `pybind11`, but there are others. Python is basically a convenient way to invoke numpy or Tensorflow or Torch or whatever. It's got numpy/scipy/sklearn/BLAS bindings etc., and is for better or worse how you do scientific computing in the mid-to-upper-mid range these days (the HPC folks have their own whole story).

It's a pain in the ass in it's own way, but you're kinda stuck with it if you want to do mainstream ML.

As a language it's dumber in some ways that JS, definitely slower in some cases, but also way less weird. Prototype chains and stuff are a cool demo that BE knew about Self and shit in the week he had to write JS, but anyone who claims they like that has Stockholm's syndrome worse than someone who thinks Ruby metaclasses make sense.

Re:Things you can’t do in Rust (and what to do instead) by mrighele on Saturday May 15, 2021 @11:15AM (#27165944)
I've been using python for many years, but these days I would prefer to use JS (or better, TS) even for backend. I find it more enjoyable to use than Python, and faster. Sure it has its warts, but if you write idiomatic code they are not much of a problem (e.g. I don't think there is a single class in the code I write, so prototype chains are a non-issue)
Re:Things you can’t do in Rust (and what to do instead) by lstamour on Saturday May 15, 2021 @12:02PM (#27166376)
I can say that if someone is sold on Python, you’re not going to convince them to move to Rust but you might convince them to move to Go. Why? Go provides better performance than Python but without the language and keyword complexity of Rust. There’s less language to learn.

That said, the more interesting question is TypeScript vs Rust. I can see how the complexity of C++ naturally leads folks to Rust. But I’ve had a hard time choosing Rust over TypeScript when trying to implement a basic service.

It’s absolutely true that Node.js web servers aren’t optimized for multi-threaded data access times and the Node.js event loop can get in the way of responsive performance.

But at the same time once you build, for example, an HTTP 1.1 web server for Node that is similar to what you’d build using semi-unsafe code in Rust and ships by default in Go standard library, it’s hard to say that JS is any less efficient than Rust when both are generally written to use async/green thread runtimes, make calls using a pool of Postgres or database connections, and either have PG return JSON or otherwise reshape and assign the results to a data model.

Given more computing power, Rust obviously wins, but if you’ve a single thread to work with, and a small buffer so after each web request is served, GC can do its thing… where are the tangible Rust benefits besides maximum speed?

I suppose I’m cheating by suggesting you could use Actix to power your Node application, but the problem I’m facing is that Rust is really complicated to learn and there are few frameworks that make it easier. The amount of published and shared knowledge there is around Go, PHP, TypeScript, Python and Ruby is enormous. Yes, Rust is clearly easier to learn than all the warts of C++, but it feels like Rust hasn’t gained enough traction to convert TypeScript fans, for example, or at least those building APIs and front ends.

I’d really like to be convinced to use Rust because of how easy it is compared to TypeScript but I haven’t seen anyone actually suggest that in practice. Go? Yes, it’s easier to learn than to understand both JS and TS and you can put up with the lack of generics by having more verbose code compared to TypeScript. But Rust? Is it just the case that these other languages are more mature such that all the blog posts have been written?

Also note that the hardest problem when getting started in any new language is package and framework selection. Unless you follow a book that has already picked a handful of packages such that you’re happily falling into the pit of success, I recognize that all languages (except maybe Rails or Spring) force the user to make hard choices upfront about their dependencies. But the only book I’ve seen that presents a coherent narrative for Rust APIs is Zero2Prod[1] and I’d feel more confident if there was at least one other similar set of learning materials.

1. https://www.lpalmieri.com/ for the book published as blog posts, https://www.zero2prod.com/ to buy.

Re:Things you can’t do in Rust (and what to do instead) by gameswithgo on Saturday May 15, 2021 @11:49AM (#27166264)
Rust gives you c++ runtime performance with compile time memory and data race safety. that is about it. less warts syntactically just by being newer.
Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Saturday May 15, 2021 @03:50PM (#27168368)
Here's one of my go-to examples. This is spawning 10 threads, each of which appends some characters to a shared string. First the C++ version:

    shared_ptr<pair<mutex, string>> my_pair =
        make_shared<pair<mutex, string>>();
    vector<thread> thread_handles;
    for (int i = 0; i < 10; i++) {
      thread thread_handle([=] {
        lock_guard<mutex> guard(my_pair->first);
        my_pair->second += "some characters";
      });
      thread_handles.push_back(std::move(thread_handle));
    }
    for (auto &thread_handle : thread_handles) {
      thread_handle.join();
    }

And now the exact same code in Rust:

    let my_string: Arc<Mutex<String>> =
        Arc::new(Mutex::new(String::new()));
    let mut thread_handles = Vec::new();
    for _ in 0..10 {
        let arc_clone = my_string.clone();
        let thread_handle = thread::spawn(move || {
            let mut guard: MutexGuard<String> =
                arc_clone.lock().unwrap();
            guard.push_str("some characters");
        });
        thread_handles.push(thread_handle);
    }
    for thread_handle in thread_handles {
        thread_handle.join().unwrap();
    }
===== Highlighting some visible differences between these two examples =====

- C++ doesn't actually need shared_ptr here. It would be happy to access a string and mutex on the caller's stack, and the only reason I didn't do it that way here was to keep the behavior as close as possible to the Rust code. However, Rust requires the reference-counted smart pointer (Arc = "atomic reference counted"), to avoid holding direct references to objects on the callers stack that might hypothetically not live long enough. Basically, Rust doesn't understand that the join loop makes it safe.* If you want to access caller stack variables from threads in Rust, there are ways to do it (see Rayon or Crossbeam), but the basic std::thread::spawn won't let you.

- Mutex in Rust is a container of one element, kind of like shared_ptr and Arc are. The MutexGuard that you get from it is also a smart pointer to the contained element. You dereference it to access the String on the inside, here implicitly with the `.` operator. This is a big part of Rust's safety story: it's syntactically impossible to access the String without locking.

- Because C++ copy constructors are implicit, moving `my_pair` into the closure invokes its copy constructor and bumps its reference count. But the equivalent syntax in Rust does a bitwise move, which doesn't run any type-specific code. So to get the effect of a type-specific copy constructor in Rust we use the explicit `.clone()` method, which bumps the reference count of our Arc. (If we had forgotten this and tried to move the original, it would be a compiler error, because Rust moves are destructive, and the compiler knows the for-loop will move more than once.)

===== My thoughts about this =====

- This Rust code is genuinely difficult for beginners to write, no doubt about it. You really have to familiarize yourself with all the relevant library types before you can get threading code to compile.

- That said, there are so many mistakes we could make in either case, and all of them are compiler errors in Rust. For example we could forget to use a lock entirely, initialize our lock guard inappropriatey, or accidentally take a shared/read lock when we meant to take a unique/write lock. Or perhaps(*), we might throw/panic before completing all the joins. Those mistakes will compile in C++ and fail TSan (or abort) at runtime, but they won't compile in Rust.

- I think the scariest mistake here might be accidentally keeping a pointer to the shared string past the point where you unlock. For example, maybe we pass the string to some method that implicitly takes a string_view of it, and stashes that view for later. Rust catches this too! It knows that references to the string borrow the MutexGuard, and it will not let them live past the point where the MutexGuard is destructed.

- I think it's interesting to ask why Mutex isn't a container in other languages. (Or at least, in other languages that support generic containers.) I think the previous bullet is the answer. It's nice to get a syntactic guarantee that you've locked the Mutex before you touch its contents, but when there's nothing stopping you from keeping a reference too long, you can't actually make the strong guarantees that you want to at compile time.

Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Saturday May 15, 2021 @08:01PM (#27170061)
Here's a runnable version of the Rust code, with some type annotations removed: https://play.rust-lang.org/?version=stable&mode=debug&editio...

And here are a few broken versions to show the compiler errors you see when you make mistakes:

- Not using Mutex at all: https://play.rust-lang.org/?version=stable&mode=debug&editio...

- Replacing Mutex with RwLock, and then taking a read lock instead of a write lock: https://play.rust-lang.org/?version=stable&mode=debug&editio...

- My favorite, trying to retain a reference past unlocking: https://play.rust-lang.org/?version=stable&mode=debug&editio...

That last example is the most condensed picture of "what Rust is all about" that I know of. Rust itself has no idea what a Mutex (or a thread) is. Mutex is just some library type. But it's able to use the borrow checker to enforce a high-level guarantee, that the contained object is never accessed without holding the lock. This guarantee is checked at compile time, with no runtime overhead. Ownership, borrowing, and lifetimes are about more than just memory safety: library authors can use them to express invariants.

Re:Things you can’t do in Rust (and what to do instead) by tene on Monday May 17, 2021 @10:31PM (#27190687)
You mention this, but I want to clarify that you only need reference counting due to using only std, not due to limitations in the language.

Scoped threads are available in crossbeam, and they're pretty great, as sometimes it's convenient to borrow something from the stack.

Here's how I'd write that with scoped threads:

    let my_string = Mutex::new(String::new());
    crossbeam::scope(|s| {
        for _ in 0..10 {
            s.spawn(|_| {
                let mut guard = my_string.lock().unwrap();
                guard.push_str("some characters");
            });
        }
    }).unwrap();
Re:Things you can’t do in Rust (and what to do instead) by oconnor663 on Wednesday May 19, 2021 @09:44PM (#27216463)
Yeah Crossbeam is awesome. And the pre-1.0 story about a similar interface that existed in std, until it was found to be unsound, is totally fascinating: https://github.com/rust-lang/rust/issues/24292. (Prior to that, std::mem::forget was marked unsafe!)

Another detail that's worth clarifying for folks reading along: The API in this example will automatically join all threads at the end of the crossbeam::scope. (That is indeed what makes it safe.) So if your goal is to fire off a background thread that will outlive the current function, you usually need to go back to std::thread::spawn and live with its 'static requirement.

Re:Things you can’t do in Rust (and what to do instead) by stagger87 on Saturday May 15, 2021 @10:44AM (#27165638)
Presumably you've read enough to know that memory safety and UB are Rust's biggest selling points? If that hasn't convinced you already, I'm not sure what would. Just keep using C++.

(I use C++ and I love it.)

Re:Things you can’t do in Rust (and what to do instead) by benreesman on Saturday May 15, 2021 @10:48AM (#27165676)
I have forlorn hopes that Rust will fix build times and I'll tolerate the abusive relationship with the borrow checker if it can move the needle on that.
Re:Things you can’t do in Rust (and what to do instead) by firethief on Saturday May 15, 2021 @11:07AM (#27165865)
Fighting with the borrow checker is just a phase you have to get through, it will click. The need to write anything that can't be done without unsafety is rare (probably never unless you are writing a data structure library).
Re:Things you can’t do in Rust (and what to do instead) by monoideism on Saturday May 15, 2021 @11:05AM (#27165831)
> UB

Undefined behavior? As in, you can confine it to `unsafe`?

Re:Things you can’t do in Rust (and what to do instead) by tialaramex on Saturday May 15, 2021 @12:26PM (#27166589)
Unsafe Code isn't allowed to have Undefined Behaviour either.

What unsafe does, is it says to the compiler:

"Hey, I know you're just a dumb machine, and you couldn't prove this code obeys all the rules that keep Rust safe, but I am very smart and I promise it actually is safe". You're also encouraged to explain yourself (to other humans, not the compiler, this isn't Wuffs) so that anybody else maintaining the code can see why exactly you believed this was OK.

Over the years, some code which was once unsafe in Rust no longer needed an unsafe block, because Rust's compiler got smarter, "Oh, I see why this is OK".

But if your unsafe code has Undefined Behaviour that's actually a serious bug, it's not what unsafe is for at all.

Re:Things you can’t do in Rust (and what to do instead) by monoideism on Sunday May 16, 2021 @09:27PM (#27179119)
That's what I thought, or at least suspected, so not sure why "UB" was listed as a Rust selling point.
Re:Things you can’t do in Rust (and what to do instead) by tialaramex on Sunday May 16, 2021 @10:47PM (#27179609)
I am not the poster in question, but I assume that they meant Rust avoids Undefined Behaviour and this is indeed a notable selling point, compared to low-level languages.
Re:Things you can’t do in Rust (and what to do instead) by GuB-42 on Saturday May 15, 2021 @11:46AM (#27166242)
Maybe Rust is not for your project, it is not a universal language, far from it. It is a language designed to make a web browser, and some projects have similar requirements, which makes Rust good for these projects too, but for some others, well maybe the much hated C++ is just better.

There is a good reason why several programming languages exist.

Re:Things you can’t do in Rust (and what to do instead) by sanderjd on Saturday May 15, 2021 @11:57AM (#27166345)
Personally, I became interested in Rust through early writing about Servo, a project driven by people who were frustrated by writing a lot of C++ out of necessity (in the Firefox codebase), which reminds me of what you're looking for here. Maybe you can dig up some of that writing, though it may be pretty out of date now.
Re:Things you can’t do in Rust (and what to do instead) by beltsazar on Saturday May 15, 2021 @10:29AM (#27165537)
For one thing, it's the only non-research programming language that can guarantee at compile time your program free from data races.