I disagree with Linus Torvalds about C++ (2009)
johndcook.com
johndcook.com
I understand Linus's argument that in large collaborative C++ projects driven by volunteers, you can easily end up with messed up code base littered with stupid mistakes. C is slightly easier to understand and deal with - relatively. Also note even fewer people actually knows what C++ features you can use it on bare metal or kernel code.
On a fun side story, Windows NT team initially had huge debates on using C++. Dave Cutler was firmly against using C++ to build OS if I remember correctly but the graphics group decided to be hip and modern and do everything in C++. After long delays and frustration graphics group had to revert to C.
void f() {
Vector<int> var1;
}I think c a novice seem much more likely to rely on undefined behavior and have an accidentally working program that leaks memory, fails to check the return value of malloc, close files etc?
That is, one can be sort of productive and "correct" in naive c++ - in c that's not really possible (well, one can be "productive" but correct is less likely?).
I can't be bothered to check the implementation now, but the allocated size must be stored somewhere. My first thought of inferring the capacity as the smallest power of two greater than the used size doesn't work as the vector size can shrink without affecting capacity.
If it's too hard to find good people or sift out bad code, even a technically good language is not helping you with your real task.
Not parent commenter either, but by far the most common answer is: "the sort of C++ dev who is happy with maintaining incredibly clunky codebases that are old enough to drink alcohol in the U.S. If you're in a well-defined, niche sector like gaming, embedded, low-latency programming etc. the code won't quite be old enough to drink, but it will still be really, really clunky, and nowhere near a "modern" standard like C++17.
Maybe you can find some good C++ devs in CAML, lisp, scala, rust comminities, but these people probably would not turn back to C++ without a strong reason.
It was 1992.
C++ is old language, however the first version of C++ standard only appeared in 1998.
Before it happened, the quality of the compilers was mediocre. Early in my career (but much later than 1992) I have used VC++ 5 and 6, they weren’t good. They were good enough C-with-classes compilers, but try slightly more complex C++ and they just crashed.
The standard library wasn’t there either, instead there were multiple incompatible STL implementations.
I'm not claiming to be highly skilled with C++ (or any language for that matter), but I've spent several years as an undergraduate TA for the year-long intro to programming series which was taught in C++. I read the textbook over several times, helped create homeworks, exams and study material, and not once have I heard of RAII or naked/smart pointers. In fact, I've never heard the word 'correctness' in reference to the idea of const variables. Is my education faulty, or is it disingenuous to call these ideas 'most basic'?
I graduated from one of the better engineering schools in my West-coast state.
https://liveblue.wordpress.com/2013/11/28/subsurface-switche...
Besides, there's really not much point in comparing, 1991 non-standardized "vector<bool> sounds like an awesome idea but first we have to find a compiler which implements inheritance properly" C++ with 2018 "you can compile template metaprogramming and constexpr stuff on commodore 64 and windows 10 and it works fine" (https://www.youtube.com/watch?v=zBkNBP00wJE)
Why new? because you don't have a heap in the kernel, or practically on a system with 20k or ram, new is also bad in real time code because underneath it is malloc and (like printf/stdio) all the mutexes that protect code that is messing with the heap structure .... and that way lies priority inversions and heisenbugs and other dark beasties ...
(for a lot of real time code new is great at the beginning of time, but not on the fly while the world is running)
You can use placement-new syntax and ~Object() (direct call to the destructor), together with malloc/free, or any other memory-allocation primitive, just like in C. You don't have to use the inbuilt new operator.
Still, C++ should be considered a near-legacy language these days. Rust (even in its no_std subset) is progressing rather quickly.
2) allocation can fail but you do not care to handle it. Your application will abort on an exception which is the best scenario.
3) allocation can fail and you want to handle it non locally (for example in a constructor). Exceptions work well in this scenario.
4) allocation can fail and you want to handle it locally: new(nothrow) is your friend. Remember to check for '!= nullptr'.
As for small memory systems, even MISRA and the NASA guidelines say no memory allocation after initialization; having a bump pointer heap is very nice. Global operator new overrides are really nice in embedded systems too, I had one for the RTOS I worked on that let you specify memory region, alignment, etc and it worked by default for allocating any C++ object for free. Obvs you have to leave code behind that new's after initialization, or frees, but that's nothing new to small systems.
Conflation of resource allocation on the one hand and construction (a.k.a. initialization) on the other.
Good C programmers do not re-invent C++ constructors and destructors, because they don't think what C++ constructors do is a good idea to do.
While C++ allows to separate allocation and initialization ("placement new") that goes against the grain of the language and its ecosystem. You're still left with constructors new-ing nested things themselves, and you're still left with exceptions from constructors while a simple return value would be better.
> A typical C or C++ programmer simply will not write anything more efficient or more robust than the methods in these libraries if they decide to roll their own.
A typical C programmer will write something different in the first place. Something that doesn't take ages to compile. Something that doesn't do allocations behind their back. Something that doesn't spew out nigh unreadable error messages if they got a simple thing wrong. Something that doesn't encourage clever code that isn't doing anything useful. Something that doesn't require loads of boilerplate and duplication (thinking of const for example) for the simplest task.
a.k.a. RAII (Resource Allocation Is Initialization). Which is very often what you want anyway.
In particular, sometimes you don’t want a bunch of allocations and locks firing on every function call and exit. C makes this behaviour explicit and C++ makes it implicit.
I've come to think of C++ as the tiktaalik of programming languages: It can live in two environments, and was an important evolutionary step in transitioning from one to the other. But, ultimately, it embodied so many design compromises that it was never going to be ideally suited to either of them.
I'm not sure why you think that placement new is against the grain of the language, it is what allows non-intrusive yet inline data structures in the first place.
Re constructors newings things, one still has the option of passing the preallocated objects via constructor parameters, or customize allocation via an allocator. The language itself doesn't have a preference.
> one still has the option of passing the preallocated objects via constructor parameters, or customize allocation via an allocator
I'd rather just allocate_the_thing(); initialize_the_thing(); do_things_with_the_thing(); free_the_thing(); which makes it very easy to pull these farther away from each other, or to perform bulk operations over many "objects". In other words, I just want to do what needs to be done, when it needs to be done, and not have to build and use awkward semantically heavy trap doors (rvalue references?) to not do the systematic things that weren't a good idea in the first place.
You can do exactly those things in C++ (operator new or allocators, T::T(), T::~T(), operator delete). The language just gives the tools to distinguish a bunch of uninitialized memory from an actual T which holds its invariant (if any).
Uninitialized memory is all I ever want. And I want to simply write to that memory when the time has come, not hide those writes in a T::T() somewhere in an isolated file with lots of braces and spaces and colons and only few things that actually happen. It's really hard to map out the codepath of a project with lots of constructors and inherited constructors 15 levels down the call stack. Same applies for running it in a debugger.
When using C++ I feel like too much of my time is spent having to understand how the abstractions work under the covers. I feel that this is somewhat pointless. Shouldn't a high level language free you from worrying about the details?
Are you talking about C++ or high level languages in general?
Either way you can come at this from multiple directions. For instance I like the way Josh Bloch designed the collection classes of Java, where you have some key types (given as interfaces) and multiple implementations as well as adapters. The focus is on the semantics and not really the implementation. For the most part you try to write code so it can take advantage of as many implementations of the same type as possible.
Rather than focus on implementation detail I think a standard library has two jobs: the first is to serve as an example of idiomatic language use. The second is to make the language useful - meaning that it should be possible to do practical things with only the standard library. Today such a practical thing might be to perform an HTTP request without having to go on an easter egg hunt.
I think one reason Go is becoming so popular is that it isn't obsessed with "purity". Remember Scheme? Remember how useless it was out of the box? It couldn't actually do anything.
c++ specifically. if I don't care about the difference between, for example, a list, a vector, and a deque, I am probably going to choose a higher level language to work in. that said, you can write container agnostic code with templates and range-based for and/or iterators if you really want.
I agree with your other points. in particular, it's annoying to have to reach for libcurl every time I want to do simple http stuff, and I have fond memories of scheme from cs 101, as beautiful and unpractical as it is.
You can, but people don't often do.
That’s no longer the case. Substandard programmers have moved towards safer GC languages.
> STL and Boost and other total and utter crap
For many parts, yes indeed, but both are optional. Boost is not even a standard library.
> typical C or C++ programmer simply will not write anything more efficient or more robust than the methods in these libraries if they decide to roll their own.
Some parts of the STL are just horrible. Look at <iostream> header. Even with my experience, I will struggle trying to roll my own IO that’s less efficient or less robust, I don’t think it’s humanly possible.
Other parts work OK but just too slow. For example, I avoid using standard collections except strings and vectors: https://github.com/Const-me/CollectionMicrobench
> to limit yourself to all the things that are basically available in C.
C++ has a problem, it doesn’t have an ABI. When you’re writing complex enough systems with it, you either invent one on top of it (see how MS did it in Windows with COM, IUnknown + HRESULT, used in DirectX, Media Foundation, .NET, UWP, and many other libraries & frameworks), or indeed limit yourself to things available in C, plus just a couple extra like unique_ptr, string and vector.
However, on the lower level, in the implementation of these components, C++ helps a lot. If you’ll look at how MS implemented C runtime library routines like printf(), you’ll find they have used a lot of C++ inside, even templates to avoid code duplication caused by char/wchar_t versions.
Of course I ignore a lot of comments, but try to go for the ones that seems intelligible.
The emacs editor really is an Operating System to it's own extent. I really fell in love with the idea of being able to just work all day with nothing but emacs, I have not gotten to that point yet though. Being able to not leave my editor for anything sounds pretty useful if done right.
Tell me more! :-)
I suspect in the long run that one will be settled in favor of the microkernel, but it will take a long long time to get there. Missed chance if there ever was one, but I can see some ulterior motives to keep the kernel as complex and hard to contribute to as possible. If everybody could write drivers then where would be the glory in that...
Everyone can write drivers. It's one of the few things we can do in monolith-land. I guess I'm probably missing your point.
Yes you are, but that's fine. I totally see why the difference between 'can' and 'actually does' is lost. The reason for that is simple: device driver writing on a monolithic kernel is something of a black art, even with all the tools we have at our disposal today. On a microkernel you'd just be writing any other user process, with access to a couple of ports and and maybe a special hook to handle hw interrupts, but other than that you would not be able to tell the difference. Debugging would be almost as easy as debugging any other user process. You could use a whole slew of high level languages to do your device driver writing. If the interpreters on the system would take care of the lower levels of interacting with the kernel to deal with IO and/or interrupts then you could do your device driver writing in interpreted languages.
But, you'll have to wait a little longer to be able to do that. Or try to locate a copy of QnX...
This is a fiction. Hint: if a "user process" can wreak havoc on the system simply by misbehaving (in a way that may or may not be malicious), as drivers interacting with low-level hardware can, it's not a user process in practice, and should not be understood as one. The whole point of making that kernel vs. user space distinction in the first place is so that user programs can't wreak havoc on the system. There are plenty of things that can and should be done in userland (and oftentimes they are, see e.g. Plan9), but drivers are not among these unless you can always rely on something like IOMMU to make sure that the hardware cannot be made to misbehave in a way that affects security guarantees.
No, it has existed roughly since the mid 80's. Source: programmed a whole bunch of stuff including very fast serial hardware drivers on systems like that.
The users process can not wreak havoc on the system, no matter how much it would misbehave in that context.
Hardware typically has pretty clearly spelled out bounds and limitations, users processes operate with less rather than more privilege than a kernel side thread would and so have much less in terms of ability to wreck the system. As an extra bonus: a microkernel is small enough that formal verification is an option.
P.S.: This comment is written just for fun. It's just an Nerf attack, a little play. Thanks.
Or with other words: While there are many reasonable good C++ programmers there are view which are really good due to the complexity of C++.
We have tons of crap anywhere due to bad code monkeys, kernel included, and these days with actual computing power keep using low level languages is a nonsense.
I'm not a fun of Go nor Rust and I can't say how hard can be write a modern kernel in a functional language like a Lisp or Haskell (thou in the past we have had LispM) however IMO we need to use high-level language to develop the same thing with less complexity and much more readability. Sooner or later any complex project will became so complex that even in FOSS world nobody can really know it enough to master it's evolution.
And there of course have been and still are operating systems written in Lisp without a single line of C. Some of them even run on decidedly non-exotic hardware like x86_64 or arm64.
I think that says it all. On top of that, Linus is in charge of the project he works on and is allowed to run it as he sees fit. Given all that, I decided to stop reading. OK, that and I already have my own impression of C++ but this intro doesn't make me want to reconsider.
The argument is not about whether Linus should be forced at gunpoint to adopt C++; it's about whether adopting C++ would be a good idea.
Deciding if something is good or bad is separate from deciding if it should be done or not. Nobody will stop you from e.g. putting pants on your head if that's what you really want, but we can have a discussion weighing the pros and cons of doing so, after which you can make a more informed decision if you choose (or not!) to listen to the feedback.