News for hackers. Stuff that matters.
Re:A brief introduction to C++'s model for type- and resourc... by greydius on Friday January 15, 2016 @09:22AM (#10909434)
Safe by convention is a ridiculous notion. I think (and I know this isn't a popular opinion here, but I'll say it anyway) that C and C++ are dying horses; these 'modern' versions and 'best practices' are not adequate solutions, evidenced partly by the fact that we can't even agree on what they should be. The next decade is going to see the rise of systems programming languages with static safety guarantees. Personally, I think Rust has a lot of potential, but we will see.
Re:A brief introduction to C++'s model for type- and resourc... by 72deluxe on Friday January 15, 2016 @09:36AM (#10909514)
C++ has had to be backwards compatible for the billions of lines of code written in it. It has managed to introduce new features and safety quite well in view of this. Perhaps the rise of systems programming languages with static safety guarantees is C++ already? You don't have to write it with "old school" methodology just because you can write it with old-school dangerous approaches.

I think that C++11 and beyond will do quite well. Sadly here in the UK at least, it has lost vast swathes of the job market to C# (likely because of C++11 taking so long to appear) but there are still a few C++ jobs (for maintaining crusty MFC codebases) or a few that specifically mention C++11.

I myself think C++11 is a great language and daily write C++03 at work through gritted teeth.

As you say though, we'll see what comes about. It is only a language after all.

EDIT: And I will add that C++ does have the benefit of having loads of libraries available to it, including GUI libraries and bindings which makes development a breeze.

Re:A brief introduction to C++'s model for type- and resourc... by lmm on Friday January 15, 2016 @09:48AM (#10909584)
> C++ has had to be backwards compatible for the billions of lines of code written in it. It has managed to introduce new features and safety quite well in view of this. Perhaps the rise of systems programming languages with static safety guarantees is C++ already? You don't have to write it with "old school" methodology just because you can write it with old-school dangerous approaches.

The very definition of static safety guarantees is that the compiler enforces them, and that's what makes them useful. C++ has great safety guarantees if written correctly - but if you can reliably write code correctly, you don't need safety guarantees in the first place!

> EDIT: And I will add that C++ does have the benefit of having loads of libraries available to it, including GUI libraries and bindings which makes development a breeze.

There are many libraries, but the important ones have mature bindings from other languages, or at least tools for generating them (e.g. Swig). That said, using them exposes you to the safety risks of C++, so you're often better off rewriting them (e.g. I worked on a Java project that initially used ffmpeg to handle some transcoding tasks - but as a result had to deal with bugs in ffmpeg that took down the whole JVM for particular inputs).

Re:A brief introduction to C++'s model for type- and resourc... by zanny on Friday January 15, 2016 @10:36AM (#10909869)
It would be neat though if GCC and Clang supported some compiler flag like Wsafe to warning on all raw pointer manipulation and raw memory addressing. Would make maintaining a C++ project and avoiding unsafe habits easier.
Re:A brief introduction to C++'s model for type- and resourc... by 72deluxe on Friday January 15, 2016 @09:51AM (#10909604)
The safety guarantees being enforced by the compiler does mean that you can (and really should) offload all the checking onto the compiler and not think you know better by casting everywhere etc.

Good point though!

Sad about your JVM - did you not monitor the state of the process you spawned to handle transcoding? Did you end up fixing the bugs in ffmpeg?

Re:A brief introduction to C++'s model for type- and resourc... by lmm on Friday January 15, 2016 @10:07AM (#10909692)
> The safety guarantees being enforced by the compiler does mean that you can (and really should) offload all the checking onto the compiler and not think you know better by casting everywhere etc.

When the set of actions that might violate the guarantees is small, circumscribed and easy to spot in code review and/or with automated tools this kind of approach works. But in C++ it feels more like today's best practices are tomorrow's unsafe constructs - it's like perl's "there is more than one way to do it", but additionally all but one of the ways are unsafe.

> did you not monitor the state of the process you spawned to handle transcoding?

That was my point - we originally tried to use JNI so that we could use libffmpeg as a library (and e.g. handle parameters and input/output as structured data rather than having to flatten them to a string command line and temporary file or pipe). But unfortunately if you do that you give up the nice guarantees of the JVM platform - e.g. a Java-native library will only ever affect its own thread, but a bug in a JNI library can take down the whole JVM. (We did ultimately move to a separate-process-for-transcoding model for exactly this reason)

> Did you end up fixing the bugs in ffmpeg?

We fixed specific bugs as we found them. It didn't feel like we were making a dent in the number there were though.

Re:A brief introduction to C++'s model for type- and resourc... by cousin_it on Friday January 15, 2016 @09:47AM (#10909577)
I wanted to write a similar comment, but then noticed that the paper claims 100% safety by using an analysis tool, not just by convention.

Agreed about the potential of Rust, it sidesteps most of these problems. Though it might introduce other problems of its own, only time will tell. I expect that Rust's future sore spots will include destructor leaks, the reliance on macros, and the tremendous complexity of traits. (Though of course I don't claim to have better solutions to those.)

Re:A brief introduction to C++'s model for type- and resourc... by kibwen on Friday January 15, 2016 @10:47AM (#10909949)

  > destructor leaks
Rust doesn't leak destructors any more than C++ (including the version of C++ presented in the OP). The only way to leak a destructor accidentally is to create a cycle (which is quite difficult to do, essentially requiring you to stuff a RefCell inside an Rc) or to have some data owned by a thread that's eternally stalled.

  > reliance on macros
Individual macros are generally regarded as convenient workarounds rather than ideal long-term solutions, and anywhere that you see pervasive macro use tends to be ripe for an RFC for a dedicated feature to subsume it.

  > the tremendous complexity of traits
No denying that traits are Rust's "deepest" feature, but that's because of a general philosophy to leverage traits to provide newly desired bits of functionality rather than introducing all-new language concepts. Removing functionality from traits wouldn't result in making the language less complex; that functionality would just end up going elsewhere.
Re:A brief introduction to C++'s model for type- and resourc... by kbenson on Friday January 15, 2016 @11:09AM (#10910124)
> Removing functionality from traits wouldn't result in making the language less complex; that functionality would just end up going elsewhere.

Yes, the Waterbed Theory of Complexity[1]. It can be useful to funnel complexity into specific areas where it's at least expected, and there may exist better mechanisms for dealing with it.

1: https://en.wikipedia.org/wiki/Waterbed_theory

Re:A brief introduction to C++'s model for type- and resourc... by cousin_it on Friday January 15, 2016 @12:15PM (#10910620)
> destructor leaks

Right, I'm not saying C++ is perfect either. I feel like Rust made a wrong turn here: https://www.reddit.com/r/rust/comments/3404ml/prepooping_you...

> reliance on macros

I'm referring specifically to try!.

Re:A brief introduction to C++'s model for type- and resourc... by Manishearth on Friday January 15, 2016 @02:48PM (#10911621)
Note that whilst the leakpocalypse made it safe to leak, it's not a common case. Leaking safely involves an explicit call to mem::forget or extremely convoluted code involving Rc cycles. Its pretty much going to happen in languages which provide refcounted pointers.

None of the proposed solutions mitigated this either. You will always be able to leak cycles. The difference was that some proposals made it possible to mark types as non-leakable, in which case they can't be placed in things which may potentially leak.

The fact that things will leak was never under question there. The decision to be made was on how safety should interact with it -- should there be a way for a type to rely on its destructor being run for the purposes of safety? The decision was that there shouldn't, and we ended up fixing two APIs which relied on destructors being run for safety, instead of adding a major language change.

Re:A brief introduction to C++'s model for type- and resourc... by cousin_it on Saturday January 16, 2016 @03:20PM (#10916668)
For what it's worth, I feel that marking types is also a mistake, and the whole machinery of OIBITs exists due to some unfortunate decisions made early on.

Maybe the cleanest solution to the leakpocalypse would be to mark RefCell.borrow_mut as unsafe, because it's problematic in two separate ways (it can both panic and create cycles). That way the safe fragment of Rust would guarantee that memory leaks can't happen and destructors always run. That would fit with the spirit of Rust, which strongly prefers 100% guarantees to 99% guarantees. Though I guess that idea was judged too inconvenient for users, and I don't claim to know what users want.

Re:A brief introduction to C++'s model for type- and resourc... by dbaupp on Saturday January 16, 2016 @08:38PM (#10917866)
Concurrency/parallelism is sometimes described as "abstraction piercing", i.e. you can't tell if something is safe for use in a concurrent code by just looking at its interface, the internals of the type and the implementation details of its functionality matter.

One way to handle this is to have each type explicitly opt-in to saying they're concurrent-safe, but this is fairly annoying, as it requires a lot of boilerplate. Boilerplate that is mostly pointless in Rust, because its rules mean most types people define will be safe, and most types that aren't safe will be built out of existing types that aren't safe. OIBITs are proxies for "safe", and are designed to strict a balance, by basically following that rule (types made out of types implementing an OIBIT automatically impl that OIBIT too).

Moving on to your specific suggestion: RefCell isn't the only way to not run destructors, for instance, one can create ownership cycles with Mutex and RWLock in a similar way, and, more broadly, threads that dead lock (or live lock) will leak their resources, as would calling std::process::exit. There's also weirder/wilder things like the following: suppose Queue<T> is a multiple-producer multiple-consumer queue type, where any instance can act as both a producer and a consumer (typical for such types), then the following code creates an ownership cycle within the queue, and so won't run the destructor of X:

  struct Msg {
      x: X,
      y: Queue<Msg>
  }

  let q: Queue<Msg> = ...;
  let q2 = q.clone(); // another handle to the same queue
  q.send(Msg { x: ..., y: q2 });
  drop(q);
Now, sure you could mark all these things unsafe, but I think that starts to make things very inconvenient, and, somewhat, weaken what `unsafe` means (it normalise its use since those things are typically totally fine). (Also, those examples are almost surely not exhaustive.)
Re:A brief introduction to C++'s model for type- and resourc... by cousin_it on Saturday January 16, 2016 @09:01PM (#10917944)
Interesting! Do you mind if I ask you a few newbie questions?

1) After some soul searching, it seems like the really important invariant to me is that all alive objects should be reachable from the stack(s) at any given moment. So I'm kind of okay with failing to run destructors due to deadlock or process exit, but not okay with leaking a cycle. Is that a sensible distinction, or is the situation even more subtle?

2) How do I make a cycle with Mutex and RWLock?

3) I don't completely understand the queue example, what exactly is the magic that allows self-reference?

Re:A brief introduction to C++'s model for type- and resourc... by dbaupp on Sunday January 17, 2016 @07:41AM (#10919302)
> 1) After some soul searching, it seems like the really important invariant to me is that all alive objects should be reachable from the stack(s) at any given moment. So I'm kind of okay with failing to run destructors due to deadlock or process exit, but not okay with leaking a cycle. Is that a sensible distinction, or is the situation even more subtle?

I think that's a reasonable distinction, but, at least for deadlocks, I'm not sure it is enough to have all the guarantees one might want (particularly around multithreading/scoping). Then again, it might be.

> 2) How do I make a cycle with Mutex and RWLock?

The same as a RefCell, just call `.lock().unwrap()` and `.write().unwrap()` instead of `.borrow_mut()`. These two types are essentially the same as a RefCell, just with more synchronisation, and fewer panics. They can block and wait for another thread to finish, at the risk of deadlocks of course, while a RefCell is restricted to a single thread, so blocking would just dead lock a thread with itself, hence a panic resolves the situation better. In fact, other than this blocking/panicking distinction, a RwLock and RefCell are almost identical: .read == .borrow and .write == .borrow_mut.

Here's a demo which creates cycles that contain a type that prints in the destructor (demonstrating that they don't run): https://play.rust-lang.org/?gist=6ea16b859e22f57fee14&versio...

> 3) I don't completely understand the queue example, what exactly is the magic that allows self-reference?

This is also essentially the same as the core RefCell/Mutex example, replacing .borrow_mut()/.lock() with .send. An mpmc Queue<T> will be isomorphic to Arc<Mutex<VecDeque<T>>> (although unlikely to be implemented as such in practice). The key is that they will reference-count the book-keeping that needs to be shared among all handles (like the start/tail of the queue), which allows creating a reference cycle.

Re:A brief introduction to C++'s model for type- and resourc... by kibwen on Friday January 15, 2016 @12:25PM (#10910681)

  > I feel like Rust made a wrong turn here
I think the broader context of "the leakpocalypse" involved a host of difficult decisions, all of them suboptimal in their own ways. Of all the options on the table, it's my opinion that Rust took the most pragmatic one, especially given that the proposals that sought to ensure "never-leak" behavior all felt like they had undiscovered holes of their own, leading to a lot of ceremony for no actual benefit.

  > I'm referring specifically to try!

I'm also referring to `try!`. :) It's a personal goal of mine this year to advocate a language-level replacement (and enhancement) for improved error-handling ergonomics.
Re:A brief introduction to C++'s model for type- and resourc... by pcwalton on Friday January 15, 2016 @03:44PM (#10911995)
Actually, I'm increasingly convinced we made the right choice there. In some other areas (exception safety) we're discovering that adding new traits to the language that infect everything has dramatically negative effects on usability.

I think of things like the leakpocalypse the same way I think of security advisories like the Go one from a few days ago. Yeah, it looks bad on paper, but the odds of being affected by it in practice are so incredibly low that it's not worth worrying about.

Re:A brief introduction to C++'s model for type- and resourc... by Manishearth on Saturday January 16, 2016 @03:28AM (#10914711)
As far as try goes, see https://github.com/rust-lang/rfcs/pull/243#issuecomment-1720... . It's reached final comment period so probably will happen soonish?
Re:A brief introduction to C++'s model for type- and resourc... by MichaelMoser123 on Friday January 15, 2016 @08:02PM (#10913595)
There is this cppcon presentation by Stroustrup where he is talking about the GSL annotations https://m.youtube.com/watch?v=1OEu9C51K2A but too bad that it all depends on this unreleased big black box proprietary code analysis tool.
Re:A brief introduction to C++'s model for type- and resourc... by MichaelMoser123 on Friday January 15, 2016 @11:01PM (#10914183)
The problem is that you probably can't trust the validator results blindly. You will end up with at least some false reports.
Re:A brief introduction to C++'s model for type- and resourc... by gpderetta on Friday January 15, 2016 @10:01AM (#10909659)
The paper is not arguing for safe 'conventions'.

It describes a (sketch of) a statically provable memory safe dialect of c++. A more detailed description is in one of the referenced papers by Herb Sutter.

Unfortunately the promised static checker is, as far as I know, yet to be released, and we will have to see how well it will work in practice and whether it is feasible to piecemeal add the safety annotations to an existing codebase.

Re:A brief introduction to C++'s model for type- and resourc... by steveklabnik on Friday January 15, 2016 @09:43AM (#10909552)
I am actually re-writing Rust's documentation on ownership right now. I'm interested to compare and contrast my stuff with this. (First draft of the first chapter is https://github.com/rust-lang/book/pull/58, I have PRs up for the other two, but they're not quite as polished yet)
Re:A brief introduction to C++'s model for type- and resourc... by krylon on Friday January 15, 2016 @06:34PM (#10913125)
In the long run, I agree with you, where new projects are concerned. At the same time, we have these mountains of C/C++ around that aren't going to go anywhere anytime too soon.

Remember the Y2K problem and how those programmers in the 60s and 70s thought that by the year 2000, surely their code would have been either fixed or rewritten.

At most, C and C++ are "dying" in the same way COBOL is - for new projects, other languages might prevail, but there are still mountains of legacy code written in it that nobody dares touch...