Announcement

Collapse
No announcement yet.

Rust For Linux Kernel v9 Patches Trim Things Down Greatly For Easier Upstreaming

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #31
    Originally posted by kpedersen View Post

    I said "core useful parts". Gonna have to strip a lot more out than just STL

    In kernel land, that will mean stripping exceptions, RTTI. Probably also excluding the use of references and RAII. Its usage will end up even being closer to C99, than K&R C is to C99.
    Actually you can keep a half of STL without any changes: everything that works without exceptions. Exceptions is the only thing that is not good for the kernel. It's an optional part of the language, so it's not a big deal.

    Comment


    • #32
      Originally posted by darkonix View Post
      I 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.
      How do you track ownership in C? If the function returns a pointer should you free it? With what function you should free it? C is very fragile. In C++ you can specify ownership and deleter function and leave no space for mistakes as resource leaks.

      Comment


      • #33
        Originally posted by piotrj3 View Post
        This 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.
        That's incorrect. For the kernel you just need to disable exceptions. Yes, some standard STL stuff won't work. But not the whole STL. So you end up with a stripped down version of STL and kernel specific containers that you use instead of std::vector or std::map. RAII, lambda, constexpr, template, overload, namespace, class, new/delete work fine and this is much more than C can do.

        It's not a theoretical hypothesis. I'm basing on my real practice for the Windows kernel drivers.

        Comment


        • #34
          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


          • #35
            Originally posted by ultimA View Post
            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.
            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.)

            Comment


            • #36
              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.)
              True, but totally irrelevant for two reasons.

              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.

              Comment


              • #37
                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.
                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 ultimA View Post
                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.
                It 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.

                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{};".

                Comment


                • #38
                  Originally posted by NobodyXu View Post
                  It 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.
                  And 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.

                  Originally posted by NobodyXu View Post
                  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{};".
                  It'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);
                  .

                  Comment


                  • #39
                    Originally posted by Sergey Podobry View Post
                    And 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.
                    You misread my reply.

                    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 Post
                    It'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);
                    .
                    Let's think about this piece of code:

                    Code:
                    std::vector<int> v = std::vector{10};
                    This person who wrote this code wants to have 10 int initialized to 0, but instead they have a vec which has only one element, 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)...}
                    }
                    People often write generic code that requires initialization of an object and having overloaded meaning when writing "T{...}" really isn't helping.
                    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.

                    Comment


                    • #40
                      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.
                      Just because a project implements dynamic dispatching (and in C of all cases) doesn't make it OOP-style.

                      Originally posted by NobodyXu View Post
                      It 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.
                      Compilers are actually known to optimize away even vtables completely if they can prove there are no current and future users for it. In a kernel application and after devirtualization this probably means compiling with LTO, which has only been possible since relatively recently with the Linux kernel, but nevertheless possible. We can also reasonably speculate that it would have gotten implemented much earlier if there had been a language binding in the kernel greatly benefiting from it.
                      Last edited by ultimA; 08 August 2022, 04:39 AM.

                      Comment

                      Working...
                      X