News for hackers. Stuff that matters.
Re:Zero to Production in Rust by verdagon on Saturday June 05, 2021 @03:21PM (#27407812)
> Rust does have a lot of complicated stuff, but almost all of it secretly turns up if you wanted to be good at C++ too.

This is mostly true. As FP and Rust have shown us, if you can treat an input data set as immutable, while building up the result data, you have a much easier time. I bring those patterns into my C++, which speaks to your point.

I'd offer one exception though: mutability xor aliasability on a per-object basis is something I wouldn't take to my C++ code. It may be the core of Rust, and it's a neat tradeoff that enables some of its other benefits, but the indirect complexity cost is too high, IME.

> Oh there is just no way it's harder to learn than C++.

I think the jury's still out on this one.

C++ has complexity, but has the benefit of a gradual learning curve. You can start with C, slowly add `virtual`, then add templates, then add the STL.

Rust has just as much complexity, and forces it all on you at once. Because of that, it is harder to learn.

Some people say Rust's rules are intuitive. I have to disagree. These years of working with Rust and teaching Rust to others have made it clear to me: though the basic concepts are simple, the architectural implications and workarounds are not.

I'm not saying C++ or Rust is better. But C++ is slightly easier to learn, IMO.

I commonly hear "But it's hard to learn how to use C++ safely!" and I generally agree with that. ASan has made things much easier in that regard, but C++ will probably never catch up enough for some use cases.

Re:Zero to Production in Rust by vvanders on Saturday June 05, 2021 @04:33PM (#27408250)
> C++ has complexity, but has the benefit of a gradual learning curve. You can start with C, slowly add `virtual`, then add templates, then add the STL.

Having seen teams go Java -> C++ and other teams go C -> C++ I don't really think that's the case. The former leans on shared_ptr everywhere, the latter ends up hitting footguns with implicit behavior around move semantics, RAII(seen more than a few use after free here) and the like.

ASAN and other tools help, but assume they are run regularly and kept to a level of rigor I haven't always seen in codebases.

Re:Zero to Production in Rust by moldavi on Saturday June 05, 2021 @05:00PM (#27408423)
To be fair, people coming from other languages lean heavily on Rc/RefCell too, and sometimes (uh oh) unsafe blocks.

In both cases, one benefits from input from those experienced in the language.

(not saying c/c++ is better than rust, just commenting on the difficulty)

Re:Zero to Production in Rust by vvanders on Saturday June 05, 2021 @05:09PM (#27408471)
Yeah, but rightly so those are "escape hatches" because you can leak memory with Rc/shared_ptr.

With C++ unless you have someone experienced on a team there's a host of "unknown unknowns" that feel like the team is making progress but then having to pay the cost when it blows up and usually when schedule pressure is near the highest point. Same for the build systems, retrofitting LTO is not a fun experience.

Rust in contrast calls out many of those things upfront, I've found those guardrails prompt conversations in tradeoffs and conscious choices(to say use Rc/RefCell) you'd be making anyway in C++.

Re:Zero to Production in Rust by moldavi on Saturday June 05, 2021 @05:29PM (#27408605)
So it's okay if rust does shared ownership, but not okay for c++?

I'm not attacking rust, btw. We all know c/c++ isn't great. Theres plenty of aspects where rust is better, and plenty where c++ is better.

But we're just talking about difficulty, and in this context it's fair to say rust isn't necessarily better than c/c++.

Re:Zero to Production in Rust by vvanders on Saturday June 05, 2021 @05:55PM (#27408742)
Shared ownership is code smell to me regardless of the language, I think Rust just makes it a bit more high friction.

Language difficulty I'm having trouble seeing how C++ isn't harder there. You have decades of features, lots of gotchas that I could rattle off and a bunch of implicit behavior that you only learn about when it blows up at runtime(if your lucky). Heck, I've seen heap corruptions stay latent in codebases for 6+ months only to have a new field added that causes them to cascade into a failure that took 3 weeks to debug across 2 different teams. I've still seen modern compilers not catch basic use after free scenarios in code today.

I won't disagree that you can get code to compile quicker in C++ but if your goal is feature velocity you're better served by a high level language. If your goal is stability, performance and memory which is the domain of systems programming then I think C++ has a bunch of hidden failure modes that Rust frontloads in an elegant way.

There are projects where you'd pick C++ for portability on platforms LLVM doesn't support or momentum with existing codebases but if I had to pick between the two my personal bias is towards Rust for all the reasons above.

Re:Zero to Production in Rust by reecko on Sunday June 06, 2021 @12:54AM (#27410886)
> Shared ownership is code smell to me regardless of the language

This is an unsubstantiated claim. If Rust makes something hard, that doesn't automatically make it universally bad. Nearly every large Rust code base I've seen uses reference counting (both `Rc` and `Arc`) a lot. Moreover, it is not practical to write general-purpose code avoiding both GC and RC because the need for shared ownership will inevitably crop up at some point. So ruling it out as code smell is a bit dogmatic.

It is also worth noting that ownership semantics is one approach (among others like GC) to memory management. In future, more languages will have some sort of ownership semantics along with GC. Nim's ORC is currently a good example.

Re:Zero to Production in Rust by moldavi on Saturday June 05, 2021 @06:21PM (#27408897)
Let's keep this on track; we're only talking about the learning curve here.

Nobody here is saying c/c++ or rust is better after their respective learning curves. No need to be defensive, they're just languages, and every language has its strengths and weaknesses.

To the point: modern c++ is easier to learn nowadays. shared_ptr and unique_ptr are as easy as Rc and Box, but without the borrow checker making things harder. One doesn't have to deal with the decades of difficulties when learning c/c++. One can choose to dive into a terrible legacy c++ project just like they can dive into an unsafe mess like Actix, but thats hardly a reflection on how easy to learn a language, just the codebase you're learning from.

And rust's front-loading of problems is a great thing! It also makes it harder to learn, which is the point here.

Re:Zero to Production in Rust by vvanders on Saturday June 05, 2021 @07:37PM (#27409331)
I think we're working from different definitions of learning curves. I include in the learning curve understanding your memory ownership model, not introducing use after free, heap corruption or other failure modes.

I would argue that if you don't understand the ownership of your data you don't really understand C++(or C) and you're still learning the language. That's usually the big shift I see when developers who have a background in higher level languages moving down to C++. I've seen plenty use after free and heap corruption happen in C++0x11 and onward codebases both staying completely within modern best practices and when code diverges since there's no guardrails(ex: std::string::c_str, std::unique_ptr::get and the like).

Once you include all the footguns that exist(yes, even in modern C++) and the legacy parts of existing codebases or code that diverges from modern C++ that's why I think it has a much higher learning curve to be producing code that is at the same quality as a passing compile from Rust in aggregate.

Re:Zero to Production in Rust by moldavi on Saturday June 05, 2021 @07:55PM (#27409422)
That's reasonable; one's threshold of "safe enough" factors in.

If one is just designing a game, or a command line tool for internal use, one needn't make it completely rock solid, and C++ has the better learning curve.

If one includes the requirement to make it safer, Rust has the better learning curve.

And then if someone actually values memory safety, they use a GC'd language and laugh at how many engineer-months and proofs it will take us to make code as safe as theirs. Sigh, such is life...

Re:Zero to Production in Rust by zozbot234 on Saturday June 05, 2021 @03:26PM (#27407844)
> I'd offer one exception though: mutability xor aliasability on a per-object basis is something I wouldn't take to my C++ code.

Rust has "interior" mutability for when you need mutable access to shared data. It works very similar to the "mutable" keyword in C++ except that it's always type-driven, as opposed to something being specified as part of a declaration.

Re:Zero to Production in Rust by verdagon on Saturday June 05, 2021 @03:31PM (#27407875)
Agreed! While it's not considered "idiomatic" Rust (from all my conversations on the Rust discords), I think that interior mutability is a totally fine thing to reach for in certain cases, at the upper levels of one's architecture.

But then, once your code has RefCell<> everywhere, you're incurring runtime overhead, at which point one might as well switch to a language that makes those tradeoffs easier to wield.

This'll get even better in the near future; a lot of languages are improving in this regard (Cone, Lobster, etc).

Re:Zero to Production in Rust by zozbot234 on Saturday June 05, 2021 @03:39PM (#27407924)
> But then, once your code has RefCell<> everywhere, you're incurring runtime overhead

The runtime overhead is quite trivial (a single word per object IIRC, which is accessed w/ simple increments/decrements/checks as needed) and work is ongoing on abstractions that don't incur any hidden overhead (called 'GhostCell').

Re:Zero to Production in Rust by verdagon on Saturday June 05, 2021 @03:59PM (#27408049)
The runtime overhead of RefCell<> is usually accompanied by some other runtime overhead. To be reachable from multiple places, it usually needs to be stored in some relatively central location.

If it's a rather short-lived object and we don't need to reuse its location, it can be in a Vec, which involves bounds checking and O(logN) calls to malloc, which is not amortized. Sometimes we can put short-lived objects in an arena, which is the best option, but they are very memory hungry, which has its own costs.

If it's longer lived, we can use a Vec with indices or a type-pool, but we risk use-after-"release", which can be a privacy risk and defeats some of the nice "sanity" properties of Rust code (this is still a good option in some cases, IMO).

If it's longer lived, and we don't want those drawbacks, we have to fall back on something like Rc or generational indices, which both have their runtime costs.

IME, only a very specific kind of use case can avoid any of this runtime overhead. When you get to the more complex use cases, especially with lots of unavoidable state, these overheads appear more and more, and make the whole situation a little less clear-cut.

(This was a rather hand-wavy explanation, I can make it more accurate if you'd like)