I have worked with a Linux kernel module that was written in C++ *and* used
floating point. From a technical point of view, it is not difficult to do. The politics of merging it upstream on the other hand...
Posted Sep 13, 2009 23:17 UTC (Sun) by bjacob (subscriber, #58566)
[Link]
Interesting...
Linus's quote leave little hope that C++ code ever makes it into the kernel, indeed.
Just for the record, here's how I would counter his claims (in the link you posted):
Quote:
"The fact is, C++ compilers are not trustworthy. They were even worse in
1992, but some fundamental facts haven't changed: 1) the whole C++ exception handling thing is fundamentally broken. It's _especially_ broken for kernels. 2) any compiler or language that likes to hide things like memory allocations behind your back just isn't a good choice for a kernel. 3) you can write object-oriented code (useful for filesystems etc) in C, _without_ the crap that is C++."
1) Doesn't matter, nobody's forced to use exceptions, there are lots of C++ project who don't (KDE for example) for a variety of reasons. So exceptions being inappropriate isn't an argument against C++ in general.
2) C++ doesn't hide any memory allocation behind your back. When you replace ptr = (T*)malloc(sizeof(T)); by ptr = new T;, you haven't hidden the memory allocation!
3) meh, if Linus is happy about the object-oriented-C style that they use in the kernel, who am I to argue against that. I just have yet to hear the details of how C++ is "crap" here. It just does this repetitive work for you, in a standardized way.
***
It's funny that Linus doesn't mention what seems to me to be the most sensible reason to oppose C++ : it's far easier to organize a community of C programmers than a community of C++ programmers, to make everyone understand and use the same coding paradigms, to review patches etc... since C is such a simple language.
Writing kernel modules in Haskell
Posted Sep 13, 2009 23:36 UTC (Sun) by cesarb (subscriber, #6266)
[Link]
Posted Sep 13, 2009 23:46 UTC (Sun) by bjacob (subscriber, #58566)
[Link]
Ah, the 2007 link is better indeed (once you take out the Linus-isms!)
These arguments are against introducing c++ throughout the kernel, object models etc. Still, coming back to the original topic --- these arguments don't apply to the case where C++ would only be used in the back-end of a kernel module.
Writing kernel modules in Haskell
Posted Sep 14, 2009 6:26 UTC (Mon) by jgg (guest, #55211)
[Link]
I've seen the 2007 mail used as a strong damning of C++ quite a few times, but honestly, I find it very strange when taken in context.
The general gist seems to be a damning of OOP principles, which I think is entirely appropriate for large swaths of git, but as usual, has very little to do with C++ in particular. The strange thing is that in the end git ended up using C for all the performance sensitive stuff and really sketchy languages like shell script for much of the hard-to-do-wrappering tasks that are painful in C..
To me the argument was never that a OOP/C++ style of programming should replace the excellent optimized inner stuff, but that a C++ style and language would have been a better, more efficient and maintainable choice than all the shell script/perl/etc.
But these days it seems a lot has been (painstakingly?) implemented in C, so no matter.
Anyhow, Linus is bang on, about most C++ programmers.. C programmers that understand and use OOP concepts tend to understand that it is just a tool and not everything needs to be done with OOP, while C++ programmers with narrow experience think everything is an OOP problem. Java programmers too. Usually makes a very long and painful mess.
To me the biggest programmer folly is to design, then execute a huge slogging painful pointless mess. You see this a lot with inexperienced programmers. Some languages (like C and C++) seem to make it a lot worse. There is ALOT of slogging to do in C if you want to handle errors sensibly.
Look at something like *swan or trousers for great examples of this in action. I had to write an IKEv2 daemon for commercial/embedded/special case/blah, and it turned out to be 8,000 LOC of C++. Does about 80% of what strongswan does and maybe another 5% that strongswan doesn't (the 5% was why this was done, no hope of fitting the 5% into strongswan without being a frickin expert at that mess). Strongswan is 140,000 lines of C. I kid you not, the difference is that great.
Did C++ cause this LOC reduction? Not really, just a smart design, a lot of care and an eye toward eliminating repetition.
Writing kernel modules in Haskell
Posted Sep 14, 2009 14:00 UTC (Mon) by marcH (subscriber, #57642)
[Link]
> Anyhow, Linus is bang on, about most C++ programmers.. C programmers that understand and use OOP concepts tend to understand that it is just a tool and not everything needs to be done with OOP, while C++ programmers with narrow experience think everything is an OOP problem. Java programmers too. Usually makes a very long and painful mess.
Aaahhh, OOP... "Dude, not everything is an object."
Posted Sep 14, 2009 0:14 UTC (Mon) by cesarb (subscriber, #6266)
[Link]
Just a note in your second point: yes, C++ can hide memory allocation behind your back. Even a seemingly simple statement like "a = b + c;" can allocate memory in C++, while in C the only way that statement will allocate memory is if the compiler has to spill registers, and even then the allocation will be small and on the stack. In C++, the same "a = b + c;" statement could read from the disk, send a network packet, and draw a smiley face on your screen.
Of course, that can only happen if you create a class elsewhere which does memory allocation (and the other evil things) on "operator+" (and if you have not decided to forbid operators in your classes). But I think Linus's point is that, once you allow the language, people will want to use the features of the language, and before long you lose the ability to tell at a glance the costs and side effects of even simple operations like "a = b" (which in C can only mean the equivalent of a simple "MOV").
In fact, if you look at it this way, the fact that C is less expressive than C++ can be a feature. Having to write things like "obj->ops->fn(obj, foo)" instead of "obj->fn(foo)" makes explicit the extra costs (in this case, an additional memory read for the vtable and the extra "hidden" parameter).
Writing kernel modules in Haskell
Posted Sep 14, 2009 0:32 UTC (Mon) by bjacob (subscriber, #58566)
[Link]
All these arguments are indeed defendable --- but again, they are arguments against using C++ throughout the kernel, and hardly constitute an argument against using C++ internally in the back-end of a kernel module.
That said, if we discuss why C++ isn't used throughout the kernel --- I understand your point. One remark though: about your first paragraph, one might turn the argument upside down and say that C is evil because a function named print_hello() may actually do a lot of malloc's and send a network packet too ;) The difference between C++ and C here is that functions in C++ may appear is more various forms than in C (operators, constructors, etc). It's really a matter of knowing what to expect: an experienced C++ programmer will understand spontaneously when an operator+ is likely to have to allocate memory for the result. Which takes us back to what is really Linus' best argument against C++ throught the kernel, and to your last paragraph... in other words, we agree.
Writing kernel modules in Haskell
Posted Sep 14, 2009 6:13 UTC (Mon) by drag (subscriber, #31333)
[Link]
Well a module is still just a hunk of the kernel and for best results, long-
term, it should be every modules goal to get integrated into the kernel
proper. Therefore its counter productive to use any language other than the C
version that is acceptable by the kernel folks.
Now the haskell thing is a interesting experiment and as such it does not
make sense to be constrained by conventions.. But it may make some change to
the status quo if something is learned from it. So it's neat.
Writing kernel modules in Haskell
Posted Sep 14, 2009 15:17 UTC (Mon) by bfields (subscriber, #19510)
[Link]
they are arguments against using C++ throughout the kernel, and hardly constitute an argument against using C++ internally in the back-end of a kernel module.
I don't see how you're using that distinction.
The bulk of the kernel is drivers. If drivers were written in a variety of languages, that would make the drivers as a whole more difficult to maintain.
Writing kernel modules in Haskell
Posted Sep 14, 2009 7:36 UTC (Mon) by alankila (subscriber, #47141)
[Link]
Quibble: a = b can be a struct copy. It will turn into a memcpy, if I recall correctly.
Writing kernel modules in Haskell
Posted Sep 14, 2009 13:20 UTC (Mon) by cesarb (subscriber, #6266)
[Link]
Oops, you are right, I forgot about that trick (which I have already used several times myself). Let me rephrase then: "a = b" in C can only mean the equivalent of a simple MOV for each byte of the variable (that is, it will read from each byte of "b" once, and write to each byte of "a" once; of course this will be optimized to read/write several bytes each time). The performance characteristics are still quite transparent.
Writing kernel modules in Haskell
Posted Sep 14, 2009 21:27 UTC (Mon) by alankila (subscriber, #47141)
[Link]
Yes. I fully agree with your basic argument.
Since Java is sort of C++'s successor, perhaps I can be justified to drag it into this discussion. There is something fairly nice about its way to have essentially two languages in it: a simple unextendable arithmetic language for doing underlying operations with -- no confusion possible about what any of the expressions mean and it's analogous to C -- and an object language which is used for extending the core language. It has plenty of the good parts of C++, I guess, but I would agree that it's far from perfect.
However, the discussion we are having now can not occur in Java. In fact, since defining classes is the only possible way you can extend Java in any sense of word, you are even encouraged to not know or care what happens behind a method. It's an unusual dichotomy, but I must agree that it works. It's sort of brilliant, even.
(I'm watching myself turn into a Java enthusiast. Oh dear.)
Writing kernel modules in Haskell
Posted Sep 16, 2009 2:37 UTC (Wed) by ringerc (subscriber, #3071)
[Link]
(I'm watching myself turn into a Java enthusiast. Oh dear.)
I'm suffering the same pain. Built-in GUI toolkit (even if it's pretty dire), sane and complete libraries, native Unicode string class (do not mention std::wstring in my presence), no build system pain, solid built-in threading and concurrency ... I'm getting to like it.
I really miss RAII, though. It's not really possible in Java as there's no way to ensure a dtor fires reliably when an object exists scope, as with stack-based instances in C++. It's a real shame and a pain point for me, as working with program flow when exceptions are involved is excruciating without RAII. If I'm missing something and there's a reasonable way to do or approximate RAII in Java, please let me know...
Writing kernel modules in Haskell
Posted Sep 17, 2009 6:10 UTC (Thu) by pynm0001 (guest, #18379)
[Link]
Just like I wouldn't write C without one of glib or apr, I wouldn't write
C++ without Qt. Just as an aside, Qt has a built-in GUI toolkit (not dire,
btw), sane and complete libraries (although not as comprehensive as Java
I'd imagine), a native Unicode string class, minimal build system pain
(usually as easy as qmake -project && qmake && make), and solid built-in
threading and concurrency.
And you get RAII.
Writing kernel modules in Haskell
Posted Sep 15, 2009 9:42 UTC (Tue) by etienne_lorrain@yahoo.fr (guest, #38022)
[Link]
> of course this will be optimized to read/write several bytes each time
I have to say that older compiler version were copying fields of structure more efficiently, because they were not optimised to compile
C++ code which may trigger constructor for each fields of the structure.
Writing kernel modules in Haskell
Posted Sep 18, 2009 1:25 UTC (Fri) by kbob (guest, #1770)
[Link]
Even a seemingly simple statement like "a = b + c;" can allocate memory in C++, while in C the only way that statement will allocate memory is if the compiler has to spill registers
#define a (buf[read(open("/dev/hda", 0), buf, sizeof buf) - 1])
#define b (send(some_sock, buf, sizeof buf, 0))
#define c (system("xloadimage /usr/share/cups/doc-root/images/smiley.jpg &"))
You were saying?
Writing kernel modules in Haskell
Posted Sep 18, 2009 4:04 UTC (Fri) by njs (subscriber, #40338)
[Link]
Don't be ridiculous, the kernel wouldn't hide magic in macro calls.
Writing kernel modules in Haskell
Posted Sep 29, 2009 16:14 UTC (Tue) by Auders (subscriber, #53318)
[Link]
Posted Sep 14, 2009 0:17 UTC (Mon) by Ed_L. (guest, #24287)
[Link]
When you replace ptr = (T*)malloc(sizeof(T)); by ptr = new T;, you haven't hidden the memory allocation!
evaluates "true" only when ptr = new T; is in fact replaceable by ptr = (T*)malloc(sizeof(T)); Are you certain you want to debate this one? ;)
C++, the steampunk language
Posted Sep 14, 2009 7:24 UTC (Mon) by felixfix (subscriber, #242)
[Link]
My experience with C++ is summed up by having replaced the simple malloc/free paradigm with THREE different ways to allocate : new/delete, new[]/delete[], and the original. Heaven help you if you mix them up. (I may have details wrong here; it's been a good long time since I had to deal with that muck.)
That is no way to design anything. I remember being disgusted with quite a few other things which I have gratefully mostly forgotten, Virtual should have been the default, I think, some pretense at giving you another knob to fine tune efficiency, You can define methods with a ridiculous number of keywords, more pretentious knobs. There are a zillion things you can do to hide the complexity of your class, to the point that there is no way to tell which operations are expensive, and debugging is a nightmare of chasing from one source file to another to see the secret details of classes to find out what little pitfalls were thrown in simply because they could be. People like to call Perl line noise, but C++ makes Perl look like a nice kindergarten language in the ways you can write write-only code, and every fool CS major thinks he is cool for doing so.
It reminds me of steampunk after it got past the initial fun stage: full of pointless knobs stuck on in an attempt to look like there's a reason behind them, when all they do is ... nothing except add clutter to make a fashion statement.
C++, the steampunk language
Posted Sep 14, 2009 8:11 UTC (Mon) by alankila (subscriber, #47141)
[Link]
C++ is, sadly, an expert's language. For good or bad, all that crap is there to squeeze out every last performance bit available -- if you know how to use them and judge them worth the effort. C++ had to beat C on its own turf, and thus every feature of C++ was compromised (or made completely optional) to ensure that C++ could compile at least as well as C.
From design point of view, C++ seems to be quite unpleasant to program with, so I agree with you on that one. I think I feel some kind of a personal laundry list banging the backside of my skull wanting to come out, but there's no point to it -- C++ is a lost cause, and as long as backwards compatibility is required there is not much improvement on the horizon.
C++, the steampunk language
Posted Sep 14, 2009 16:17 UTC (Mon) by tjc (guest, #137)
[Link]
My experience with C++ is summed up by having replaced the simple malloc/free paradigm with THREE different ways to allocate : new/delete, new[]/delete[], and the original.
Since you bring it up, do you happen to know why C++ requires a separate form (new[] v. new) for allocating and deallocating arrays?
I'm aware that arrays are converted to pointers in parameter declarations and (most) expressions, but I don't think that's an issue here. There should be enough information in the symbol table to identify an object as an array and [de]allocate memory for it without resorting to a special form.
C++, the steampunk language
Posted Sep 14, 2009 16:21 UTC (Mon) by avik (subscriber, #704)
[Link]
delete[] needs to call the destructors of every element of the array, so it needs to know it is destroying an array.
C++, the steampunk language
Posted Sep 14, 2009 16:30 UTC (Mon) by nye (guest, #51576)
[Link]
Note that there is a bit more to it than that, otherwise it would be okay to use delete on an array of POD types, which it isn't (see my other post). That's undoubtedly the root reason though.
C++, the steampunk language
Posted Sep 14, 2009 16:26 UTC (Mon) by nye (guest, #51576)
[Link]
Posted Sep 14, 2009 17:43 UTC (Mon) by tjc (guest, #137)
[Link]
Thanks for the link. There is some other useful information on that page; see the post by Andrew Grant.
IIUC the size of an object could be stored in the symbol table, but that would only work with objects within lexical scope-- a dynamically allocated object returned from a library function would still be a problem, since there is no portable way to attach size information to an object in C.
C++, the steampunk language
Posted Sep 14, 2009 17:37 UTC (Mon) by jgg (guest, #55211)
[Link]
> My experience with C++ is summed up by having replaced the simple malloc/free paradigm with THREE different ways to allocate : new/delete, new[]/delete[], and the original. Heaven help you if you mix them up. (I may have details wrong here; it's been a good long time since I had to deal with that muck.)
And C has an infinite variety of alloc/free functions..
Foo *foo = calloc(1,sizeof(Foo));
Foo *foo = LIBRARY_foo_Alloc();
Foo foo; LIBRARY_foo_Init(&foo);
Foo **foo = malloc(n*sizeof(Foo *)); for (int i = 0; i != n; i++) foo[i] = LIBRARY_foo_Alloc();
It is ever so much fun in mixing and matching them! Heaven help you if you use the incorrect free for the alloc that was chosen!!
new/new [] is actually a substantial increase in API uniformity compared to C and the multitude of libraries.
C++, the steampunk language
Posted Sep 14, 2009 18:28 UTC (Mon) by felixfix (subscriber, #242)
[Link]
Why are you dragging in library routines? They have nothing to do with core C.
C++, the steampunk language
Posted Sep 14, 2009 20:06 UTC (Mon) by jgg (guest, #55211)
[Link]
> Why are you dragging in library routines? They have nothing to do with core C.
Wow, that is just so pedantic. You do realize that the ISO C standard includes a library and that library includes functions like I described (fopen/fclose for instance). SUS adds more. It isn't like there is another way to do this ..
C++, the steampunk language
Posted Sep 14, 2009 19:46 UTC (Mon) by bronson (subscriber, #4806)
[Link]
Er, by definition C++ has all of C's "infinite variety" of alloc/free functions. Plus it adds more of its own (it's great fun watching people incorrectly override delete[]... from a distance).
If you say, "well, don't use X in C++" then I'll just say "don't use X in C."
C++, the steampunk language
Posted Sep 15, 2009 14:33 UTC (Tue) by nix (subscriber, #2304)
[Link]
Yes, but in C++ code you don't use that 'infinite variety': you wrap whateveritis up in an object and call the appropriate C allocation/freeing functions *once*, from the constructor and destructor of that object. Then you can consistently use the new/delete family of functions *everywhere* else. So the chaos of allocation and freeing functions that can easily be mixed up transforms into a single allocation/freeing function for all objects and a single one for all arrays of objects (which are sort of deprecated now 'cos the STL types are just as good). And it becomes impossible to use the wrong allocation and freeing functions anywhere, and memory leaks become harder to accidentally introduce as well (as the majority of object allocations are on the stack, so construction and destruction are automatic).
(The same applies to malloc()/free(): they shouldn't be used in well-written C++ programs, at all. They're not typesafe.)
Writing kernel modules in Haskell
Posted Sep 17, 2009 6:17 UTC (Thu) by pynm0001 (guest, #18379)
[Link]
> > When you replace ptr = (T*)malloc(sizeof(T)); by ptr = new T;, you
> > haven't hidden the memory allocation!
> evaluates "true" only when ptr = new T; is in fact replaceable by ptr =
> (T*)malloc(sizeof(T)); Are you certain you want to debate this one? ;)
that a C++ "ptr = new T;" is capable of expressing? You weren't going to
use that ptr uninitialized were you? This is 2009, there's no reason to
be using uninitialized structs!
Writing kernel modules in Haskell
Posted Sep 15, 2009 0:24 UTC (Tue) by jengelh (subscriber, #33263)
[Link]
>I have worked with a Linux kernel module that was written in C++ *and* used
floating point.
VMware WS has, or used to have, some C++ (IIRC, only for some little templates, there was not much too much visible C++ classes, operator-overloads or otherwise)
The latter is not particularly hard ever since the FPU state is properly saved and restored.