Announcement

Collapse
No announcement yet.

Google Engineers Lift The Lid On Carbon - A Hopeful Successor To C++

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

  • Originally posted by coder View Post
    Check out the "mix-in" pattern, sometime. The 3 ways I use multiple inheritance are: mix-ins, interfaces (Java has these), and the diamond pattern (i.e. to separate common implementation from common interface). I'm not sure what you mean about MI creating problems. I've done all 3 for more than 15 years and never really had any problems with them (once I figured out how virtual inheritance interacts with constructors!).
    I think what people refer to as problematic is precisely that extra cognitive load. You need to keep in mind how the language defines which implementation to use when multiple classes at the same level of inheritance implement the same method. C makes it easier because you'd use fake classes that force on you an explicit decision, Python makes it easier because (IIRC?) it makes you tell it the class always, in C++ there is a well defined way to pick it if you don't specify, but you need to remember which it is (IMO it's simpler to just be explicit and call it a day). Single inheritance obviously doesn't require you to keep that present, as only the lowest level will be called if you don't specify.
    It's not that it can't be done right or that it's undecidable or anything like that, it's just that you need to use an extra slot of your limited working memory to keep track of this.

    Originally posted by coder View Post
    Obviously, operator overloading has caveats, but it does tend to cut down on the number of named temporaries you need, and ties in nicely with templates. The downsides can be managed with clear guidelines about what operators can be overloaded and which semantics they should have for which sorts of types.
    I think operator overloading is only problematic when people attempt to give stuff ad-hoc meanings. No, you can't "multiply" BPF programs, thank you very much. You can, however, intuitively add two vectors to result in the appended one (not that it's a good idea where performance matters to do it that way). But that's what code review is for, a human checks that no weird semantics are introduced or rejects the patch.

    Originally posted by coder View Post
    I think there's a lot to be said for constructors and destructors, especially when the RAII style is used. It definitely reduces potential for leaks and significantly improves code density, allowing you to focus more on the algorithmic aspects. I also can't believe there wouldn't be a lot of opportunities to benefit from templates, in the kernel.
    And that's where I see value in Rust (which doesn't mean something better couldn't come soon), it enforces it at the language level and checks it for you. Just like "types were useful" so eventually static typing became popular. I don't see a language without that or something more powerful being worth migrating a C++ codebase.

    Originally posted by coder View Post
    You can write bad code in any language, but C++ definitely has more potential pitfalls than many. Good C++ style, which is mostly about negotiating that minefield, takes a long time to learn.
    And it's very context dependent as well, which means somebody who learned "good C++ style" for user space will make a mess in kernel space and vice-versa. STL heavy code is probably a good idea for user space, but would be a lot of work for core kernel devs to keep up with and introduce too much bloat for a kernel, exceptions have the same problems (it's a no-go for a kernel, and panic [closest thing to an exception in Rust] is the main reason Rust almost got rejected outright), while someone who learned by coding for the kernel would in turn be accustomed to different data structures and a more limited scope, losing on some useful features for user space.
    TBF that's also true for Rust and one of the main reasons the Rust experiment is moving slow. Patterns such as assuming a global allocator, arbitrary crates from the internet and what not are not appropriate for the kernel, and the people behind the Rust effort has been working hard in making it possible to avoid all that. I used C++ for bare metal as well and it wasn't a bad experience at all either.

    Originally posted by coder View Post
    Yeah, it'll be interesting to see how the Rust driver experiment shakes out. I haven't been following it too closely, but I wonder how many drivers are actually using it, so far.
    Not many, the point for now is not about quantity but about how representative of how it'd look AFAICT. Re: unsafe, I don't think that's really a problem, as long as it's small sections. While Rust is definitely better used with little unsafe sections, the point is that the ratio between safe and unsafe code favors the first, as unsafe is the only part that needs to actively be audited for UB and memory errors. Compare that to C where you can break stuff at any place, without explicit warning for the reviewer.

    Comment


    • Originally posted by sinepgib View Post
      I think what people refer to as problematic is precisely that extra cognitive load.
      If you're going to use inheritance, then my contention is that MI can be used to produce flatter hierarchies (I rarely have more than 2-deep) and thus reduces cognitive load in that way. I think MI gets bad press, due to worst-case scenarios that some people dream up & the general sense that it sounds more complicated.

      Originally posted by sinepgib View Post
      C makes it easier because you'd use fake classes that force on you an explicit decision,
      Depends. The nice thing about C++ is that if inheritance is really what you want, C++ does it in a declarative way that you can clearly see up-front. In C, function pointer members can be set and overwritten at any point. So, it imposes a requirement that the software project have a regular mechanism & convention for initializing & overwriting them to avoid any confusion.

      As I mentioned, another big use for function pointer members is to model state machines. In C++, if you see pointer-to-member variables or std::function<> members, either it's that or a simple form of dependency-injection. In C, there's the added uncertainty of whether it's really just modeling inheritance.

      Originally posted by sinepgib View Post
      It's not that it can't be done right or that it's undecidable or anything like that, it's just that you need to use an extra slot of your limited working memory to keep track of this.
      For mix-ins and interfaces, you typically won't have name-collisions between the methods of your different base classes, which is why I think it's mostly a non-issue.

      Originally posted by sinepgib View Post
      But that's what code review is for, a human checks that no weird semantics are introduced or rejects the patch.
      Right. What you need is clear policies + code reviews to ensure they're followed.

      Originally posted by sinepgib View Post
      somebody who learned "good C++ style" for user space will make a mess in kernel space and vice-versa. STL heavy code is probably a good idea for user space, but would be a lot of work for core kernel devs to keep up with and introduce too much bloat for a kernel,
      Well, I think there'd be a very high degree of overlap, like at least 80%. You might start with something like C++ Core Guidelines and then have your own kernel-specific rules that take precedence whenever there's a contradiction.

      And yes, STL is obviously not suitable for in-kernel use. However, the kernel has plenty of algorithms and datastructures, some of which could be templated. A big advantage people overlook about C++ is that STL gives you higher-quality algorithms and datastructures than most C programmers would bother to implement. Likewise, I wouldn't be surprised to learn that parts of the kernel still use more primitive algorithms and data structures, which means there's room for improvement if they'd transition to a language which supports high-quality generic implementations.
      Last edited by coder; 25 July 2022, 04:42 PM.

      Comment


      • Originally posted by coder View Post
        If you're going to use inheritance, then my contention is that MI can be used to produce flatter hierarchies (I rarely have more than 2-deep) and thus reduces cognitive load in that way. I think MI gets bad press, due to worst-case scenarios that some people dream up & the general sense that it sounds more complicated.

        Depends. The nice thing about C++ is that if inheritance is really what you want, C++ does it in a declarative way that you can clearly see up-front. In C, function pointer members can be set and overwritten at any point. So, it imposes a requirement that the software project have a regular mechanism & convention for initializing & overwriting them to avoid any confusion.

        As I mentioned, the other use for function pointer members is to model state machines. In C++, if you see pointer-to-member variables or std::function<> members, either it's a simple form of dependency-injection or someone is using them to model a state machine. In C, there's the added uncertainty of whether it's really just modeling inheritance.

        For mix-ins and interfaces, you typically won't have name-collisions between the methods of your different base classes, which is why I think it's mostly a non-issue.
        Yes, all very good points. I just want to clarify one thing: I'm not defending C OOP patterns over C++ in general, but only pointing out that the "issues" with multiple inheritance that one could think of in C++ aren't there. Of course, you have a different set of issues and (IMO, and apparently yours as well) C++ is vastly superior to C in its implementation of OOP in general.

        Originally posted by yump View Post
        Well, I think there'd be a very high degree of overlap, like at least 80%. You might start with something like C++ Core Guidelines and then have your own kernel-specific rules that take precedence whenever there's a contradiction.
        Yeah, and certainly things like smart pointers would probably translate 1:1, same for RAII, which are the most important improvement over C in terms of safety.

        Originally posted by yump View Post
        And yes, STL is obviously not suitable for in-kernel use. However, the kernel has plenty of algorithms and datastructures, some of which could be templated. A big advantage people overlook about C++ is that STL gives you higher-quality algorithms and datastructures than most C programmers would bother to implement. Likewise, I wouldn't be surprised to learn that parts of the kernel still use more primitive algorithms and data structures, which means there's room for improvement if they'd transition to a language which supports high-quality generic implementations.
        Yes, that's precisely what I loved from C++ when I learned it. C gives you essentially nothing out of the box, and its lack of any kind of serious generics makes decent data structures particularly hard to implement and use. Now, specifically for the kernel, I wouldn't be surprised if drivers didn't make use proper use of its facilities, but a lot of work goes into optimizing its data structures. That said, a nice wrapper around templates would be a huge deal in terms of usability.

        Comment


        • Originally posted by Sergey Podobry View Post
          Rust has a lot of buzz in the internet. But in real life I visit a job board and see the following numbers:
          c++ - 138
          python - 182
          java - 235
          c# - 199
          golang - 52
          rust - 5

          Who in sane mind wants to get 5 job proposals instead of hundreds? So almost none will invest time into learning Rust. The same goes from the company perspective: do you want your product to get locked with a not widespread technology and hard to find developers?
          fewer positions means higher salary, less competency and higher chance of passing the interview. Don't you see COBOL or PHP positions that have very high proposed salary due to the lack of programmers in those languages

          Comment


          • Originally posted by coder View Post
            If you have to argue about the size of vanity walls, then it seems to me you've given up on the technical arguments.

            IMO, there are some arguments not worth having. Vanity walls is one of them. People who raise this point are not likely to be won over by anything you say.
            I was replying to someone who claimed you could count the number of companies using Rust in production on your fingers. It was a perfectly valid counter to where they took things.

            Comment


            • Originally posted by arQon View Post
              MI is something that in reality almost never solves more problems than it creates, and a language that doesn't have it is not in any way inherently unsuitable for general purpose, but "simple" inheritance DOES map to an absolutely enormous set of real-world problems, and Rust's workaround for not supporting that is as clumsy as "switch(p->type) {" is.
              However, it won't necessarily stay that way. The Rust developers' rationale for not providing some form of implementation delegation is "We're still waiting to see which of multiple mutually incompatible ways to provide it, each with their own trade-offs, before we promise to give it language-blessed support in perpetuity."

              It's a completely forward-compatible decision.

              Comment


              • Originally posted by ssokolow View Post
                I was replying to someone who claimed you could count the number of companies using Rust in production on your fingers. It was a perfectly valid counter to where they took things.
                Sure, but I think the chance you were able to change their mind/position with that counter is very low. It's too easy to write off such vanity walls, because the standard for getting on it is probably nonexistent. I bet you just need one person toying with it, in the bowels of XYZ MegaCorp and it gets added to the wall the same as if Rust were central to their business strategy.

                In contrast, membership lists do mean something, in the case of standards bodies where members must pay dues and/or contribute their employees' time.

                Comment


                • Originally posted by coder View Post
                  Sure, but I think the chance you were able to change their mind/position with that counter is very low. It's too easy to write off such vanity walls, because the standard for getting on it is probably nonexistent. I bet you just need one person toying with it, in the bowels of XYZ MegaCorp and it gets added to the wall the same as if Rust were central to their business strategy.

                  In contrast, membership lists do mean something, in the case of standards bodies where members must pay dues and/or contribute their employees' time.
                  It's a little different than that, since Rust's vanity wall:
                  1. Is something you have to ask to be added to (at least, last I checked)
                  2. Has an explanation of what they're using it for on each entry.
                  ...but you make a good point, so I'll point at the membership wall for the Rust Foundation. You can't count that on your fingers either.

                  Comment


                  • Originally posted by phuclv View Post

                    fewer positions means higher salary, less competency and higher chance of passing the interview. Don't you see COBOL or PHP positions that have very high proposed salary due to the lack of programmers in those languages
                    Wrong. Salary depends on demand and proposition in the market.

                    Comment


                    • Originally posted by cynic View Post
                      what? you can set and satisfy a time constraints regardless of the system you're running on.
                      That comment is so hopelessly wrong that it took me several minutes to even understand what (I *think*) you were actually trying to say, but even if so it's still wrong, just in a more normal way.
                      It doesn't help that you changed the context from what I was actually replying to, so maybe reading the post would have helped.

                      > Of course there might be extreme load situation where it is not sufficient, but your question is wrong anyway.

                      Two quick points: first, you mean you don't have the experience to understand the question; and second, it was rather obviously rhetorical.

                      Yes, "load" - not "extreme load" or other attempts to hedge - is one of the reasons why "10ms" obviously isn't, and can't be, guaranteed, or even close to it.

                      Anyway: I'm going to interpret your statement as attempting to say that what you think is that "When Go runs GC, it tries to do so in slices of not more than 10ms", right? If so, there may be some point in continuing with this. If that wasn't it then lets get out of here before wasting any more time on this.

                      Comment

                      Working...
                      X