Originally posted by kpedersen
View Post
Announcement
Collapse
No announcement yet.
Rust For Linux Kernel v9 Patches Trim Things Down Greatly For Easier Upstreaming
Collapse
X
-
Originally posted by darkonix View PostI have used C++ as a 'better C' replacement and it certainly has its uses. Having said that, I don't believe that it would provide any really significant advantages it in the Linux kernel and it would require extra effort to ensure that undesired C++ features are introduced.
It would be interesting to have an actual list concrete benefits and features that should be excluded because they are not appropriate for the Kernel to understand in more deep the real impact.
Comment
-
Originally posted by piotrj3 View PostThis is far worse then just "plugging" kernel allocator into STD (what theoretically can be done). It also implies that if anything under the hood of STD (or any feature) can't use exceptions (oh they do use exceptions) among few other things. For example MSVC for windows has flags to force disable exceptions and RTII. Practically means you simply can't use std, stl, raii, exceptions among many other things. And at this point C++ dumps down a lot to almost the level of C.
It's not a theoretical hypothesis. I'm basing on my real practice for the Windows kernel drivers.
Comment
-
Yes, Linus rejected C++ hardly back then. It seems though most people only know this through hearsay and hardly anybody knows/remembers the actual mail he wrote about the reasons. Due to this, an important detail seems to have gotten lost over the time: He rejected C++ exclusively or almost exclusively due to the object-oriented programming style. Strip OOP from C++ (meaning for example not being able to uses classes and RAII) and you're left without any meaningful improvement over plain C.
Rust in comparison provides certain safety guarantees even if you implement something in non-OOP-style. In practice though the proposed Rust modules for Linux rely heavily on objects and inheritance, It is possible Linus' opinion of OOP has changed over the years, but if I'd have to guess he's just answering to corporate interests by allowing Rust in the kernel.Last edited by ultimA; 07 August 2022, 05:14 PM.
Comment
-
Originally posted by ultimA View PostRust in comparison provides certain safety guarantees even if you implement something in non-OOP-style. In practice though the proposed Rust modules for Linux rely heavily on objects and inheritance, It is possible Linus' opinion of OOP has changed over the years, but if I'd have to guess he's just answering to corporate interests by allowing Rust in the kernel.
C++ was built around the 80s/90s obsession with implementation inheritance (i.e. subclassing).
Rust is about as aligned to that as C is. Rust supports interface inheritance. (i.e. You can declare that, to implement trait/interface A, you must also implement traits B and C, and then anything that specifies trait A in its interface constraints can also use methods defined by traits B and C. That's it.)
- Likes 3
Comment
-
Originally posted by ssokolow View Post
Bear in mind that there are two different types of inheritance.
C++ was built around the 80s/90s obsession with implementation inheritance (i.e. subclassing).
Rust is about as aligned to that as C is. Rust supports interface inheritance. (i.e. You can declare that, to implement trait/interface A, you must also implement traits B and C, and then anything that specifies trait A in its interface constraints can also use methods defined by traits B and C. That's it.)
First reason is, the difference is an implementation detail, but Linus's objection was to the programming style, and that is still very much OOP even in Rust (as far as the proposed kernel framework is concerned). You still have an inheritance hierarchy where types serve as organizational units for methods and/or data - one of the major if not the defining characteristics of OOP.
Second reason is, you can actually get the exact same kind of inheritance in C++. Use an abstract base class for your interface type, give the derived class the "final" keyword, and at call site use the known derived type instead of the base's type. This will give you the functionality of an interface without any virtual calls thanks to the devirtualization done in the compiler. In other words, you could do the same in C++ as in Rust with no difference in either function or efficiency for a kernel framework.Last edited by ultimA; 07 August 2022, 09:19 PM.
- Likes 1
Comment
-
Originally posted by ultimA View Post
First reason is, the difference is an implementation detail, but Linus's objection was to the programming style, and that is still very much OOP even in Rust (as far as the proposed kernel framework is concerned). You still have an inheritance hierarchy where types serve as organizational units for methods and/or data - one of the major if not the defining characteristics of OOP.
Needs a filesystem? Define a list of functions and put them in a vtable for it and file descriptor. You can also skip some functions and let the linux kernel provides its default implementation for you.
Want a module? Define a list of functions and put them in a vtable.
Originally posted by ultimA View PostSecond reason is, you can actually get the exact same kind of inheritance in C++. Use an abstract base class for your interface type, give the derived class the "final" keyword, and at call site use the known derived type instead of the base's type. This will give you the functionality of an interface without any virtual calls thanks to the devirtualization done in the compiler. In other words, you could do the same in C++ as in Rust with no difference in either function or efficiency for a kernel framework.
IMHO the real reason for rejecting C++ is because it is a mess.
Its language design is inconsistent and overly complex for no benefit, e.g. you have at least 3 ways to initialize an object and two of them have the same syntax (list initialization and initializer list initialization).
And initializer list initialisation also messes with default initialization using "auto a = Class{};".
- Likes 2
Comment
-
Originally posted by NobodyXu View PostIt is not zero-cost in C++: The object you created would have a 8-byte vtable pointer regardless of whether you use it or not.
Originally posted by NobodyXu View PostIMHO the real reason for rejecting C++ is because it is a mess.
Its language design is inconsistent and overly complex for no benefit, e.g. you have at least 3 ways to initialize an object and two of them have the same syntax (list initialization and initializer list initialization).
And initializer list initialisation also messes with default initialization using "auto a = Class{};".Code:my_struct a; my_struct a = b; my_struct a = { 0 }; my_struct a = { .data = 0 }; my_struct a = { .data = 0, .val = 2 }; my_struct a(b);
Comment
-
Originally posted by Sergey Podobry View PostAnd you think Rust magically implements dynamic dispatch without adding extra data? You know you don't have to write kernel code with abstract factories and virtual inheritance everywhere. Don't know why but when people argue about C++ they think only about this kind of code.
ultimA, who I was replying to, wrote about a case where no dynamic dispatch but still used abstract class in C++ to emulate trait in Rust.
That is the point I wanted to counter, because that is not zero cost in C++.
A better solution would be of course, to use CRTP or concept to emulate trait in Rust, though the former is very hacky and the later needs people to either use boost, which uses a lot of hacks, or upgrade to C++20.
Originally posted by Sergey Podobry View PostIt's not a mess, it's versatility. And a lot of that comes from C. You can write in C:Code:my_struct a; my_struct a = b; my_struct a = { 0 }; my_struct a = { .data = 0 }; my_struct a = { .data = 0, .val = 2 }; my_struct a(b);
Code:std::vector<int> v = std::vector{10};
You might say that this person just needs to take more time to read the cpp language reference https://en.cppreference.com/w/cpp, but then what about this:
Code:#include <utility> template <class T, class ...Args> auto initialize(Args &&...args) -> T { T{std::forward(args)...} }
If the type "T" has an initializer list constructor, things get much more complicated and cause confusion.
So people just keep using the old "T(...)" instead.
- Likes 1
Comment
-
Originally posted by NobodyXu View Post
I highly doubted this is a problem since the Linux kernel itself uses OOP programming style.
Needs a filesystem? Define a list of functions and put them in a vtable for it and file descriptor. You can also skip some functions and let the linux kernel provides its default implementation for you.
Want a module? Define a list of functions and put them in a vtable.
Originally posted by NobodyXu View PostIt is not zero-cost in C++: The object you created would have a 8-byte vtable pointer regardless of whether you use it or not.Last edited by ultimA; 08 August 2022, 04:39 AM.
Comment
Comment