← Back to context

Comment by Animats

3 days ago

"Longer term, we will build on this to introduce a safe Carbon subset. This will be a large and complex undertaking, and won’t be in the 0.1 design."

If they can't get safety right at the design stage, they'll never get it right. We already have D and Zig in this space.

Zig is nowhere near memory safe. Even some basic semantics (passing arguments as values or references) are horribly broken. https://github.com/ziglang/zig/issues/5973

  • no need for memory safety to be in the language. It can still be checked at compile-time:

    https://www.youtube.com/watch?v=ZY_Z-aGbYm8

    • This is a cool project, but it doesn’t address my original issue with Zig, which is that the language’s semantics is not even specified. That is, we cannot define what a “memory safe Zig program is” as we cannot even define what a Zig program is! (Unless you define the semantics of a Zig program in terms of the implementation/translation to IR, which is fragile / bad.)

      Second, I would be surprised if the static analyses in the tool are precise enough for real-world Zig programs. For example, it is undecidable to determine whether a function “takes ownership” of an argument pointer. In particular, if you want to avoid false negatives, the “free after transfer” case needs to be conservative, but then you almost certainly will flag false positives.

      1 reply →

Given that Carbon's space is "languages with full interoperability with C++," I don't think D and Zig are in that space.

As to "getting it right" - things are not so simple. The emphasis on memory-safety soundness is based on some empirical hypotheses, some better founded than others, and it's unclear what "getting it right" means.

From a software correctness perspective, the road to sound memory safety is as follows: 1. We want to reduce the amount of costly bugs in software as cheaply as possible, 2. Memory unsafe operations are a common cause of many costly bugs, 3. Some or all memory bugs can be eliminated cheaply with sound language guarantees.

The problem is that 1. memory safety refers to several properties that don't all contribute equally to correctness (e.g. out-of-bounds access causes more serious bugs than use-after-free [1]), and 2. soundly guaranteeing different memory safety properties has different costs. It gets more complicated than that (e.g. there are also unsound techniques that have proven very effective to consider), but that's the overview.

It is, therefore, as of yet unclear which memory safety properties are worth it to soundly guarantee in the language, and the answer may depend on the language's other goals (and there must be other goals that are at least as important, because the empty language guarantees not only all memory safety properties but all (safety [2]) correctness properties, yet nobody uses it as it's useless, while a language like ATS can be used to write many useful programs, but few use it because it's just too costly to use well). The goal is always to find the right balance.

For example, Java soundly guarantees lack of use-after-free at the cost of increased memory footprint; that may be "getting it right" for some programs but not all. Rust soundly guarantees lack of use-after-free at the cost of imposing strong and elaborate typesystem constraints (that, as is often the case, are more constraining than the property they guarantee); that, too, may be "getting it right" for some programs, though not all. Zig guarantees lack of out-of-bounds access in a simple language at the cost of not guaranteeing lack of use-after-free, and that may also be "getting it right" for some programs but not all.

So what "getting it right" means always depends on constraints other than safety (Rust and Zig want to consume less memory than Java; Java and Zig want to be simpler than Rust; Java and Rust want to guarantee more memory safety properties than Zig). If Carbon wants to be more interoperable with C++ than Java, Rust, or Zig, then it will have to figure out what "getting it right" means for Carbon.

[1]: https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html

[2]: https://en.wikipedia.org/wiki/Safety_and_liveness_properties

  • > As to "getting it right" - things are not so simple. The emphasis on memory-safety soundness is based on some empirical hypotheses, some better founded than others, and it's unclear what "getting it right" means.

    It means eliminating undefined behavior, and unplanned interaction between distant parts of the program.

    • Eliminating undefined behaviour is a means to an end (reduces problematic bugs, but not all undefined behaviour is equally responsible to such bugs), and it's not a binary thing (virtually all programs need to interact with software written in languages that don't eliminate undefined behaviour, so clearly there's tolerance to the possibility of undefined behaviour).

      Don't get me wrong - less undefined behaviour is better, but drawing a binary line between some and none makes for a convenient talking point, but isn't necessarily the sweet spot for the complicated and context-dependent series of tradeoffs that is software correctness.

      7 replies →

  • Splendid reply! I'm a big fan of Carbon and so I really appreciate when people make solid arguments for its tradeoff space.

  • I counted the word “sound” in this reply 8 times. When I the word sound there is always the word Rust nearby. It is just a coincidence, of course.

Swift seems to be doing a decent job of this (and C++ interop for that matter)

  • > Swift seems to be doing a decent job of this

    It keeps adding keywords and it has become way harder to keep it in your head. It’s over 220 at this point. Don’t take my word for it, Swift creator doesn’t agree with its current direction either.