Live data from Hacker News

Why Safety Profiles Failed

circle-lang.org

161–170 of 233 posts

Re: Why Safety Profiles Failed

#161
post #151

Earlier quoted context omitted.

> But most developers refuse to write anything more than C++98. I think the bigger mistake is equating memory safety with C++11 smart pointers. They buy you a little, but not the whole buffet. There are a lot of C++ developers that think memory safety is a skill issue and if you just use "best practices with C++11 or higher" then you get it - when evidence proves to the contrary.

Smart pointers, containers... There are plenty of best practices that would give memory safety but nobody uses them (and not for cases where in rust you would have to use unsafe and thus there is good reason). Which is why safety profiles are so interesting, they are something I should be able to turn on/off on a file by file basis and thus easily force the issue. Of course profiles don't exist yet (and what is propo…

Safe C++ is also something you turn on file by file.

Re: Why Safety Profiles Failed

#162
post #125
post #84

Earlier quoted context omitted.

It's a tick-the-box-for-compliance item like when Microsoft had a POSIX layer for Windows NT.

Microsoft eventually learned that keeping full POSIX support would have been a better outcome in today's server room if they had done it properly instead. Likewise, pushing half solutions like profiles that are still pretty much a paper idea, other than what already exists in static analysers, might decrease C++'s relevance in some domains, and eventually those pushing for them might find themselves in the position t…

We can dream of what it would be like with full POSIX support on Windows, but it was a pipe dream to begin with. There are some major differences between Windows and POSIX semantics for things like processes and files. The differences are severe enough that Windows and POSIX processes can’t coexist. The big issue with files is that on POSIX, you can conceptually think of a file as an inode, with zero or more paths pointing to it. On Windows, you conceptually think of a file as the path itself, and you can create mandatory locks. There are other differences. Maybe you could address these given enough time, but WSL’s solution is to basically isolate Windows and Linux, which makes a ton of sense.

Re: Why Safety Profiles Failed

#163

Earlier quoted context omitted.

That's a good point. There's many times in a C++ codebase, where I'd see or write a seemingly innocuous function, but it has so many assumptions about lifetimes, threads, etc that it would make your brain hurt. Of course we try to remove those or add a comment, but it's still difficult to deal with.

There are reasonably good c++11 conventions for lifetimes - if it is a unique_ptr you own it, otherwise you don't and shouldn't save a copy. Almost nobody follows them, but they are good conventions and you should, and write up a bug if someone else isn't. Similar, for threads, keep your data confined to one thread, but explicit where you move/copy it to a different thread (note I said move or copy - the first thread…

> There are reasonably good c++11 conventions for lifetimes [...] Almost nobody follows them [...]

I swear I'm not trying to be snarky or rude here, but is it actually a "convention" if almost nobody follows it? This seems like one example of my general issue with C++, in that it could be great if everyone agreed to a restricted subset, but of course nobody can coordinate such agreement and it doesn't exist outside companies large and important enough to enforce their own in-house C++ standards (e.g. Google).

Re: Why Safety Profiles Failed

#164

Earlier quoted context omitted.

I think maybe it's because lifetime annotations can get arbitrarily complicated. If you look at enough Rust code you'll definitely see some function signatures that make your head hurt, even if they're vastly outnumbered by simple ones. A guarantee that the comprehension complexity of that part of your code will always be below some low ceiling is tempting.

What are the "arbitrarily complicated" cases of lifetime annotations? They cannot grow beyond one lifetime (and up to one compilation error) per variable or parameter or function return value.

Mostly involving structs. Someone at work once posted the following, as a slightly-modified example of real code that they'd actually written:

  pub struct Step {
      pub name: &'a str,
      pub stage: &'b str,
      pub is_last: bool,
  }

  struct Request {
      step: &'a Step,
      destination: &'c mut [u8],
      size: &'b Cell>,
  }
To be sure, they were seeking advice on how to simplify it, but I imagine those with a more worse-is-better technical sensibility arguing that a language simply should not allow code like that to ever be written.

I also hear that higher-ranked trait bounds can get scary even within a single function signature, but I haven't had cause to actually work with them.

Re: Why Safety Profiles Failed

#165
post #4

Really glad to see this thorough examination of the weaknesses of profiles. Safe C++ is a really important project, and I hope the committee ends up making the right call here.

> Safe C++ is a really important project What makes you say this? It seems to me like we already have a lower-overhead approach to reach the same goal (a low-level language with substantially improved semantic specificity, memory safety, etc.); namely, we have Rust, which has already improved substantially over the safety properties of C++, and offers a better-designed platform for further safety research.

> It seems to me like we already have a lower-overhead approach ... Rust

Rewriting all the existing C++ code in Rust is extremely high-cost. Practically speaking, that means it won't happen in many, many cases.

I think we want to find a more efficient way to achieve memory safety in C++.

Not to mention, Rust's safety model isn't that great. It does memory safety, which is good, but it's overly restrictive, disallowing various safe patterns. I suspect there are better safe alternatives out there for most cases, or at least could be. It would make sense to consider the alternatives before anyone rewrites something in Rust.

Re: Why Safety Profiles Failed

#166

Earlier quoted context omitted.

What are the "arbitrarily complicated" cases of lifetime annotations? They cannot grow beyond one lifetime (and up to one compilation error) per variable or parameter or function return value.

Mostly involving structs. Someone at work once posted the following, as a slightly-modified example of real code that they'd actually written: pub struct Step { pub name: &'a str, pub stage: &'b str, pub is_last: bool, } struct Request { step: &'a Step , destination: &'c mut [u8], size: &'b Cell >, } To be sure, they were seeking advice on how to simplify it, but I imagine those with a more worse-is-better technical…

In general, you can usually simplify the first one to have one lifetime for both, and in the second, you’d probably want two lifetimes, one for destination and the others all shared. Defaulting to the same lifetime for everything and then introducing more of them when needed is better than starting with a unique lifetime for each reference.

I think you two are ultimately talking about slightly different things, your parent is trying to point out that, even if this signature is complex, it can’t get more complex than this: one lifetime per reference means the complexity has an upper bound.

Re: Why Safety Profiles Failed

#167
post #165
post #4

Earlier quoted context omitted.

> Safe C++ is a really important project What makes you say this? It seems to me like we already have a lower-overhead approach to reach the same goal (a low-level language with substantially improved semantic specificity, memory safety, etc.); namely, we have Rust, which has already improved substantially over the safety properties of C++, and offers a better-designed platform for further safety research.

> It seems to me like we already have a lower-overhead approach ... Rust Rewriting all the existing C++ code in Rust is extremely high-cost. Practically speaking, that means it won't happen in many, many cases. I think we want to find a more efficient way to achieve memory safety in C++. Not to mention, Rust's safety model isn't that great. It does memory safety, which is good, but it's overly restrictive, disallowin…

Folks who want to propose alternatives should do so! Right now, you’ve only got the two: profiles and Safe C++. There are also two that aren’t proposals. It have a semblance of a plan: “graft Hylo semantics instead of Rust semantics” and “scpptool.” Realistically, unless something else concrete and not “could be” is found at the eleventh hour, this is the reality of the possible choices.

Re: Why Safety Profiles Failed

#168
post #159

Earlier quoted context omitted.

What's interesting to me about this is that from what I understand, lifetime annotations are not present in Rust because of a desire to include information for the use of developers, but because without them the compiler would need to brute-force checking all potential combinations of lifetimes to determine whether one of them is valid. The heuristics[0] that the compiler uses to avoid requiring explicit annotations…

There’s some truth to both. What’s good for computers is often good for humans, but there’s a balance to be had. The elision rules are an acknowledgment that being 100% explicit in surface syntax is going a bit too far, even if it’s important info for the computer to have.

Fair enough! The part that always stuck out to me is that there were other potential designs that could have been made around how (and which) lifetime information would be specified. I think sometimes people might not realize that the we didn't get stuck with the requirements we have for lifetime annotation today due to validation requiring exactly that set of information or an indifference to the burden it might place on the programmer to specify it; the developer experience was at the forefront of deciding how this should work, and as you say, weighing all of the factors that entails is a balance.

Re: Why Safety Profiles Failed

#169

Earlier quoted context omitted.

What are the "arbitrarily complicated" cases of lifetime annotations? They cannot grow beyond one lifetime (and up to one compilation error) per variable or parameter or function return value.

Mostly involving structs. Someone at work once posted the following, as a slightly-modified example of real code that they'd actually written: pub struct Step { pub name: &'a str, pub stage: &'b str, pub is_last: bool, } struct Request { step: &'a Step , destination: &'c mut [u8], size: &'b Cell >, } To be sure, they were seeking advice on how to simplify it, but I imagine those with a more worse-is-better technical…

But you are specifying that all members of Request except step.is_last have arbitrary unrelated lifetimes (shouldn't some of them be unified?) and you are simply exposing these lifetime parameters to Request client code like you would expose C++ template parameters: a trivial repetition that is easy to read, write and reason about.

Re: Why Safety Profiles Failed

#170
Why is `f3` safe?

My thought (which is apparently wrong) is that the `const int& x` refers to memory that might be freed during `vector::push_back`. Then, when we go to construct the new element that is a copy of `x`, it might be invalid to read `x`. No?

Is this related to how a reference-to-const on the stack can extend the lifetime of a temporary to which it's bound? I didn't think that function parameters had this property (i.e. an implicit copy).

Post reply on HN