Hacker News new | ask | show | jobs
by einpoklum 940 days ago
FWIW, I think Bjarne and other C++ magnates have a plan for eating Rust's lunch by allowing for "safe"/"unsafe" within C++.
4 comments

I mean, sure, Bjarne calls his proposed way forward "safety profiles".

Most fundamentally, this completely misunderstands the nature of the problem. This is a technical change, but the most important problem C++ has is cultural. So, they're not even addressing the right problem. In his original talk about this Bjarne even repeatedly describes his approach as a "strategy" which practically begged someone to say "Culture Eats Strategy For Breakfast" but no-one did.

But let's imagine that C++ culture magically is fixed by pixies or whatever, leaving only technical problems, which safety profiles could address. The next big problem is that Rust's safety is compositional. The many different kinds of "safety" delivered via Bjarne's "safety profiles" don't compose, safety A + safety B = no safety. So this makes it largely useless from a software engineering point of view.

Once you've cleared these two fundamental obstacles you're back to more mundane limitations like timing. Rust 1.0 shipped in 2015. There are teams out there already with many years of Rust experience in practice. But Bjarne's "Safety Profiles" aren't available in your C++ compiler today, and won't be for years to come, perhaps many years. Are you confident that starting this far behind the pack will be OK?

> but the most important problem C++ has is cultural

That part, Bjarne and others have been working on for at least two decades I think. There's a lot of indoctrination/education about "staying safe" so to speak, through better coding practices, extended standard library facilities, static analysis and so forth. And from the little I can see, this is seeping into the C++ culture.

> The many different kinds of "safety" delivered via Bjarne's "safety profiles" don't compose

I'm not familiar enough with the details. But, about Rust - I was under the (possibly wrong) impression that you have the binary of either safe or unsafe: https://doc.rust-lang.org/std/keyword.unsafe.html

> Are you confident that starting this far behind the pack will be OK?

You're counting the wrong thing IMHO. If you count software systems of note, or add up their sizes; or count developers; or count organization; or add up turnover; etc. - its Python, Java, C, C++ in some sort of order that are at the head of the pack. Rust has certain benefits which make it attractive to jump onto its bandwagon - but it needs a lot of bandwagon-jumping to take the lead. If you can achieve more or less the same thing by just fiddling with your C++ development environment, then people might just not switch.

> I was under the (possibly wrong) impression that you have the binary of either safe or unsafe

No, that completely misunderstands what the unsafe keyword is for. Rust has some very strict rules to preserve safety and everybody has to obey those rules. However, in safe Rust you don't need to think about that - or even know what the rules are exactly - because the safe Rust subset always obeys the rules. In unsafe Rust you are responsible for upholding all the rules, which means you need to properly understand what the rules are and be careful to do your job properly, the same responsibility you have in every single line of C++.

Another way to think about it is that "unsafe" means "trust me, this is OK". You may find that a more helpful way to understand what unsafe blocks do, but the reason I don't prefer it is that people (including Herb and Bjarne) seem to imagine we're just "switching off" the safety rules, and that's not what happens in any way, semantically, syntactically or de facto. Suppose I have an group of three integers (indexes start at zero) let group = [1, 2, 3]; println!("{}", group[5]); -- that won't work, Rust will reject that because it's a bounds miss†. But if we replace that println! with println!("{}", unsafe { group[5] }); the Rust compiler doesn't shut up and let us do it, in fact it complains even more, in addition to saying we can't do an out-of-bounds access it also warns that this unsafe block is futile, unsafe doesn't make bounds misses magically OK.

† We can tell the Rust compiler we insist on seeing this through to the bitter end, it will emit the program, and then when this code executes there's a bounds miss and it panics. The default is to reject programs which always just panic when executed.

If culture wanted safety strategy in the compiler, wouldn't it need to standardize it?

>There are teams out there already with many years of Rust experience in practice.

They routinely use nightly version, no?

> They routinely use nightly version, no?

Depends on what you mean by "routinely." In 2020, the last year that the annual survey published these numbers, 8.7% of Rust programmers used exclusively nightly. It has been dropping every year.

Some people do occasionally use nightly; at my job, most code is on stable, but there are a few projects that do currently require a couple of nightly specific things.

I'm skeptical of the value of adding on "safe / unsafe" to C++ at this point. It's a bit like adding type annotations to Python. Better than nothing I suppose, but there's 30+ years of C/C++ that doesn't and will never be opted-in to these features, and the value declines rapidly when only 10% of the codebase (including dependencies) can be considered "safe" vs. when 99.9% of it can be.

https://cor3ntin.github.io/posts/safety/

> I'm skeptical of the value of adding on "safe / unsafe" to C++ at this point.

Me too. I've went down the road of a safer C/C++ a decade ago. So have many others. It's not impossible. But backwards compatibility is really tough. The existing attempts at a better C or C++ did not work out.

After three years of Rust, I have some misgivings. Rust does many things right, and the rigor does get you reliable programs if you stick to safe Rust, which I do. But there are problems.

- The single-ownership thing is useful but very restrictive. Lack of back references is a serious problem. Yet, so often, you want to have something that talks to its owner. Refcount everything, and you've re-invented Python and moved the problem to run time. If you have to use handles and hashes, you're lost the value that Rust added.

Something like static-analyzed safe weak back references is needed, and that's a hard theoretical problem. Think of this as working like single strong forward references and weak back references that can become strong only temporarily. Compile time checking like the borrow checker would enforce rules that eliminated the need for reference counts. This is probably possible, and is hard to do in a way that is not too restrictive to be useful. Someone has to work through the common design patterns for trees, lists you can modify in the middle, and such. Good PhD topic for someone.

- Traits turn out to be useful for only a limited class of problems. Traits are not a substitute for classes. Converting a class-oriented program to Rust is very tough.

Once new Rust programmers get past the syntax, those two issues are the big ones that prevent conversion of existing programs to safe Rust. There's a big impedance mismatch. You can't just convert; you have to redesign. Which is hard.

Sounds like something they could try. We'll see what happens. It's not like I expect C++ to "roll over" and just declare that they don't care anymore if people use the language.
Profiles will help on the domains where C++ is going to stay for a long time, like HPC, GPUs, game development, GCC/LLVM.

However it is kind of late in domains where Rust, or other safer languages are already being used. They won't rewrite back into C++.

> domains where Rust ... [is] already being used

The point is that Rust usage is still quite limited. This is a bit like C++ and D, two decades back; or perhaps even Scala and Java. The analogy isn't perfect, but the point is you had a language with a lot of potential usability-domain overlap which addressed some or many pain points and failures of the older, more popular language - but the older language embraced some of the alternative ideas, adopted them in a more-or-less compatible way, and made it not-attractive-enough to switch. So the newer languages lost momentum, and at least in the case of D - stopped gaining users and eventually sank into oblivion.

> other safer languages ... won't rewrite back into C++.

I mostly agree. Except... that some safe languages, like Java, pay for safety with a lot of overhead. And Dennard scaling is over. So, over time, there is some pressure to replace Java, or maybe C# code with something closer-to-the-metal. But we'll see.

D suffered from lack of focus, and company sponsoring, hence why it hardly mattered to C++ folks.

The domains that Java and .NET took away from C++ aren't coming back to C++, even if now they feel the pressure to have AOT and value types with better low level coding primitives.

Additionally Java and .NET applications that get rewritten, most likely will be in one of those C++ wannabe successors, even if C++ is part of the equation by using GCC/LLVM backends.

The thing is, that the "C++ successor language" sometimes ends up being C++ itself, a decade or two later.

As an example, take this question from 2008:

"How do I tokenize a string in C++?" https://stackoverflow.com/q/53849/1593077

A very popular, straightforward, and traditional-style answer to this question, , given early on, was:

  vector<string> split(const char *str, char c = ' ') {
      std::vector<std::string> result;
  
      do {
          const char *begin = str;
          while(*str != c && *str) { str++; }
          result.push_back(std::string(begin, str));
      } while (0 != *str++);
      return result;
  }
but a recent answer is:

   auto results = str | ranges::views::tokenize(" ",1);
which is in lazy-evaluated functional style, and doesn't even directly utilize the fugly standard C++ string class. This example is of course a bit simplistic (since the main change exhibited here is in the standard library), but the point is that the language has demonstrasted strong abilities to reconfigure how users tend to write code. But - perhaps I'm giving it more credit than it's due any this won't comen to pass.