Hacker News new | ask | show | jobs
by jeroenhd 1597 days ago
I much prefer Rust over C++, but I find that the problems of C++ have little to do with the language itself.

I've been watching the videos by Andreas King on SerenityOS and the code is so clean that at first I wondered what programming language I was even looking at. I see the SerenityOS codebase as proof that if C++ programmers wanted to write modern, elegant, readable code, they definitely could.

In practice, though, most C++ programs are full of legacy code or are written by people who don't necessarily know about or agree with modern ways to program C++. It's easy to write beautiful code if you also wrote the memory manager and standard library in modern C++, but most people don't have that luxury.

By being created with a more modern standard library, Rust has an advantage over C++. There is no legacy code to remain compatible with and there is no real way to write "old-fashioned" Rust because the project hasn't existed for long enough. I've seen plenty of terrible, ugly Rust, most of it in my own personal projects. The strictness of the language and standard toolset helps, but it's far from a guarantee that enterprise Rust will be readable and clear.

1 comments

Having acquired C++ into my toolbox in 1993, and thus lived through its adoption over C (which still owns several domains after 50 years), I am bettting that Rust at 30 years of age into production will suffer similar fate.
Even though Rust's Editions don't solve everything they make a huge difference and they also change the nature of the conversation around such evolution.

I think the built-in array type is illustrative. In both languages (C++ and Rust) the initial 1.0 language offers a built in array type that is provided with built-in syntax and parsing but isn't as good as the user-made container types, so on day one the situation is OK, yeah, we do have arrays but you should likely avoid them.

In C++ that just remains the case, C++ 20 has poor built-in arrays and a note saying we built another array type that you should actually use, it's in our standard library.

Meanwhile in Rust they've been improving their built-in arrays, using const generics, implementing IntoIterator for arrays, and so on. Rust 2021 in a compiler today has pretty nice built-in arrays that behave how you'd expect for a container, a sophisticated programmer might notice that Default isn't implemented for your array of 64 integers, but such sharp corners are now few and far between and further refinements continue.

The resulting conversation is more open to change, even though Editions can't actually do magic they can conceal some pretty deep compiler magic like the hack to enable IntoIterator for arrays yet keep working Rust 2015 and Rust 2018 code that assumed into_iter() on an array will go via a reference. Being able to get to 90% of what people wanted with no magic meant the conversation about extra magic happened and it might otherwise not have.

Editions also spur language innovations that make further edition work easier. Rust 1.0 did not have any way to talk about an identifier if it collided with a keyword, which of course means if you reserve a new keyword now you can't access identifiers which used the now-reserved name. Rust 2018 introduces raw identifiers to fix that, if you really insist on naming your function "try" you can write r#try despite the existence of the keyword try.

I think these benefits are cumulative, and although Rust 2045 might have some cruft it will have a lot less than C++ 23 let alone C++ 44.

I don't buy into editions, for me I hardly see them any different from language version switches available across programming languages.

Mainly, because:

1 - They require the whole code, including all third party dependencies to be available to the compiler;

2 - There is the issue about possible inconsistencies across Rust compilers, when they start to be more widespread;

3 - They are relatively constrained the scope, e.g. semantic differences across versions and how that can be handled across crates public API

Let's see how editions take care about the many items that are yet to stabilise.

Naturally Rust being 30 years younger (approximately), it will always get less cruft.

Maybe by 2045 it can manage to do the same play C++ did on C, and there will be a LLVM replacement in Rust, while at the same time, there will be domains that regardless how much cruft C++ has gained, they will continue to use, just like it almost impossible to take C out of UNIX clones and embedded, no matter how much C++ has tried.

The requirement to have all the source if you're not happy with C-style ABI boundaries comes from Rust itself not from its Editions. C++ leaves a bunch of performance on the table here because it insists on pretending your code from last century should get to dictate how a CPU designed last year works.

Hyrum's law will indeed bite multiple Rust implementations, as it already bites Rust on non-x86 CPUs because a low level language cannot entirely conceal implementation details. This is already a huge leap over C++ where you get to tickle previously undetected Undefined Behaviour if you change compilers because (safe) Rust stays safe even if you're astonished that e.g. documentation saying "the order is not defined" really means "the order is not defined" despite the fact you tested it on your laptop last week and that's how it worked. Your bad program might have bugs but it doesn't suddenly exhibit nonsense behaviour.

Fundamentally Rust's Editions are about the fact that we don't get it right first time every time. In C++ having settled on the claim that (quoting Stroustrup) "this array concept is inherently low level" the built-in array is basically abandoned as unusable garbage forever because to do otherwise would admit a mistake. In contrast Rust says sure, arrays don't yet have all the features you expect of first class containers, we will improve the language to deliver that.

I think this is a healthier philosophy and it's already successful. It isn't a panacea, but it is a very noticeable improvement.

As to taking care of items that are yet to stabilise, what's to see here? Even for something like generators that is far from finished, the keyword is reserved already, you probably wouldn't wait for an edition to land it, once it was stable you just flip the toggle and it works.

(All responding to 1) A. Binary dependencies were a mistake. B. No, editions absolutely do not require all dependencies to be fully available in source. Editions are purely a front end thing and as long as you have enough info for the api/abi, you're fine. C. Headers are still source code. You cannot use any dependency without partial source, meaning we'd be stuck with that anyway.
C headers don't give away implementation.

If Rust doesn't want the enterprise and game development markets it is ok, there is enough space for all.

Enterprise is very much a trailing indicator. On the whole Enterprise will adopt Rust the same way it adopted Version Control and the Internet, years late and reluctantly. Nobody making those decisions knows the first thing about technology, but that cuts both ways. It means there aren't going to be executives at Mondelez International chasing their software engineers to use Rust because it's a good idea, but it also means despite lobbying by C++ consultants, those executives don't care that an internal team started using Rust for a new project.

As to Game Development, well, one of the things Rust has been trying to do is avoid toxic people and if you wanted a concentrated supply of toxic people the video game industry is where you'd look. I expect there will be a lot of Rust in or near video games in the next decade, but I already pity the people working on them.

Definitely. I think Rust's more restrictive nature will leave it a little better than C and C++, but as technology evolves, every language will eventually show its age.