3 ms·
Agreed about the inability to write C, but the part about C++ is simply not true. I don't know about "better" in the general sense, but for the specific use ca
by geofft 5y ago
Agreed about the inability to write C, but the part about C++ is simply not true.
I don't know about "better" in the general sense, but for the specific use case of the Linux kernel, Linus has identified some entirely reasonable objections (though aggressively worded) to C++: https://lkml.org/lkml/2004/1/20/20 https://lkml.org/lkml/2004/1/20/20
- the whole C++ exception handling thing is fundamentally broken. It's
_especially_ broken for kernels.
- any compiler or language that likes to hide things like memory
allocations behind your back just isn't a good choice for a kernel.
- you can write object-oriented code (useful for filesystems etc) in C,
_without_ the crap that is C++.
Those objections do not apply to Rust, which avoids exception handling, avoids implicit allocations, and has a much smaller OO system that resembles what the kernel does for filesystems. Those objections continue to apply to C++.
There are good, principled reasons to accept Rust and continue to reject C++.
(There are also good reasons to believe that C++ doesn't solve any of the problems with human inability to write correct C, meaning that it wouldn't be worth the cost of adding a new language: https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/ https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/)
- quotemstr 5y agoThe passage you've quoted is exactly the sort of angry technical schlock that's held back Linux specifically and the industry generally. > the whole C++ exception handling thing is fundamentally broken Not an argument. It's the closest thing in Linus's excretion of unfounded technical opinion to an argument, but it's nevertheless not an actual case for anything. Don't like exceptions in C++? Don't use them. (That said, exceptions aren't "fundamentally broken" no matter how many times Linus repeats that baseless slander.) > any compiler or language that likes to hide things like memory allocations behind your back just isn't a good choice for a kernel This is a general-purpose tirade against any abstraction whatsoever. Good software engineering is all about judiciously "hid[ing] things", including memory allocation. And as it turns out, Linux has plenty of abstractions, some of which involve memory handling. Also, you don't have to use any particular abstraction with C++: you get to choose the abstractions. The language doesn't force any on you. Besides: Rust can do the same sort of abstractions that Linus claims disqualifies C++ as a "good choice for a kernel". It's almost as if C++ was fine even back in 2004 and that the only difference between then and now is that Linus has matured. > you can write object-oriented code (useful for filesystems etc) in C, _without_ the crap that is C++. This is a restatement of Linus's opinion, not an argument. You can write everything in assembler too: why take on the baggage of the heap of crap called C?
- deleted 5y ago[deleted]
- geofft 5y agoI agree that the email does not set out a solid argument and the "angry technical shlock" is unclear - that's what I was getting at by "aggressively worded". I think there exists a solid and reasonable argument along these lines, even if Linus did not phrase it, though, which is what I'm getting at. (And I suspect Linus and others do believe that argument, even if they're not good at communicating it, so it would be worth engaging it.) It's true that you could write C++ without exception handling, and that you get to choose the abstractions. But it matters what the language makes easy for you - what is idiomatic and conventional in the language - what programmers who use that language have come to expect their libraries to do. Otherwise you could just say that we can solve our string problems in C without switching languages by simply using length-prefixed strings and buffers and not relying on NUL termination. After all, the kernel doesn't use a userspace standard library, and even in userspace there are string-handling libraries in C that avoid those problems (e.g., http://bstring.sourceforge.net/ http://bstring.sourceforge.net/ or https://github.com/antirez/sds https://github.com/antirez/sds). But the fact remains that the kernel has its own implementations of strcat and sprintf nonetheless (in the lib/ directory), simply because C programmers expect them. And people call NUL-terminated strings "C strings" and length-prefixed strings "Pascal strings," even though you can do length-prefixed strings just in C and NUL-terminated strings just fine in Pascal. It is very hard to write abstractions in C++ that work the way the abstractions in Rust work and are still natural and easy to use. No one is disputing they're possible to write. But if you look at the blog post I linked, it demonstrates that even with the benefit of decades of experience in C++ and knowledge of what Rust is doing, and even with additional language features, and even with the input of people who did in fact choose their abstractions (std::string_view was based on libraries local to Google, LLVM, and Bloomberg), you still do not get the level of safety that the equivalent Rust feature has. Concretely, 1. C++ has language-level features (most importantly, try/catch/finally) that make error handling via exceptions easy and natural to use. Rust has language-level features (most importantly, pattern matching on sum types) that make error handling via a result type easy and natural to use. You can of course choose not to use exceptions, but you're giving up a good language feature and you don't have language support for the thing you want to do instead. This is much like saying "Don't like NUL-terminated strings? Don't use them" - technically true, but have fun avoiding string literals. 2. This is not a general-purpose tirade against abstraction. It is a very targeted tirade against implicit conversions to heap-allocated types, which are natural and idiomatic in C++. See my comment https://news.ycombinator.com/item?id=27749301 https://news.ycombinator.com/item?id=27749301 elsewhere in this thread for details on exactly what Linus is objecting to and why it is entirely reasonable for a kernel to object to it. Again, you could certainly decide to avoid implicit allocations in your nonstandard library, but it is not idiomatic C++. 3. C++'s object model is legitimately quite complex, involving things like multiple inheritance, partially-constructed objects during the constructor, and phrases like "morally virtual base". It works - there's definitely a lot of working C++ in the world - but that level of complexity isn't needed by the kernel, and (certainly in my personal experience) it's easy to get into deeply confusing situations. The kernel also cares about things like fitting objects into cachelines. The kernel doesn't need multiple inheritance with the ability to have different offsets into an object depending on what pointer type you're using, but it does need the ability to specify that objects implement multiple interfaces that carry no data (what the kernel calls "operations structures," and what Rust calls "traits"). In C++, the only mechanism the language gives you for this is multiple inheritance. There are use cases where full multiple inheritance is useful, and C++ is preferable to Rust for such cases. The Linux kernel is not one of them. It's true that you can do all the things Rust can do in C++ if you try hard enough. But I'd reiterate the point which you made clearly, that human beings simply do not seem able to write flawless C in practice, even though it is theoretically possible, because it is simply not idiomatic. From the blog post I linked, it seems like there's no reason to expect that asking humans to write flawless and unidiomatic C++ will work out any better.