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 arQon View Post

    That's an absolutely nonsensical statement. "Under 10ms" on *what*, exactly? A 5990X? A Raspberry Pi? A single-core 600MHz washing machine CPU? Under what sort of allocation load?
    what? you can set and satisfy a time constraints regardless of the system you're running on.
    Some Java GCs do the same. G1GC has a 200ms pause time but you can modify it if you need to.

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

    Comment


    • Originally posted by coder View Post
      A few years after Go's introduction, I read an article about how one of Go's designers was marveling at its failure to grab the interest of the general C++ community. Replacing C++ was one of their explicit aims.
      I haven't been in the Go world long enough to remember those statements, so I might be wrong here.

      However, I've seen many Rob Pike's talks about the reasoning behind the choices they made when designing Go and there is absolutely no clues it was trying to replace C++ as a general language: they're basing it on completely different premises.

      As far as I know, Go was meant to get rid of some C++, Java and Python codebases inside Google (for different reasons for each language) but was not intended as a general replacement for C++

      Anyway, as I stated, I'm still learning the Go background and history, so, if you have interesting resources on the topic I'd like to learn!




      Comment


      • Originally posted by arQon View Post
        That's an absolutely nonsensical statement. "Under 10ms" on *what*, exactly? A 5990X? A Raspberry Pi? A single-core 600MHz washing machine CPU? Under what sort of allocation load?
        I have no substantial experience with garbage collectors or languages that use them, but I think it's instructive to look at it as a proportion of execution time. That would mean if it runs once per second, that it takes 1% of execution time. Since faster CPUs are faster both at allocating memory and freeing it, an efficient garbage collector could conceivably impose a similar amount of overhead on a fast CPU as a slow one.

        Of course, it's unreasonable to assume you need to do the same amount of GC for all workloads. Something like a compiler should lean on GC very heavily, while deep learning is mostly dominated by raw computation. Hence, the target of 10 ms rather than an absolute percentage, because certain programs might have to run it more frequently than others. The other consequence of a 10 ms target is simply that the GC be partitioned into parcels of work small enough that you can always complete useful amounts of work in that amount of time -- even on low-end CPUs.

        Perhaps a bigger variable than the CPU type is actually the amount of RAM a garbage collector has to manage. Here's where something like a big server app could be at more of a disadvantage than a small web app.
        Last edited by coder; 25 July 2022, 07:22 AM.

        Comment


        • Originally posted by sinepgib View Post
          Under whatever they're testing on, most likely some AWS instance due to the niche they cover.
          It sure would be interesting if Google used AWS instances...

          Comment


          • Originally posted by coder View Post
            I doubt that. C -> C++ is a vastly greater evolution than C++ -> Rust. This means one of two things: either we're converging on the "ideal" programming language (for mainstream uses), or that Rust is much more of an interim evolutionary step than anything wholly new. And for something to have staying power for the next 50 years, I think it needs to do a more comprehensive job of addressing the next 50 years' evolution in computing. I doubt Rust is up to that task, but that's just my opinion.


            I think you lean too heavily on this point. C++ has a lot of baggage, including emotional baggage, cultural, bad press, and historical issues with compiler support. It could have been used in the kernel and could have been done to good effect. The reasons it wasn't weren't purely technical.

            Also, they're only enabling Rust for use in drivers. Maybe more, in the future, but even that much hasn't landed in a shipping kernel release.



            Oof. You sure won that argument! The best way to win over the doubters is obviously to call them insane.


            If you didn't notice, that post did have some claims of a technical nature that you conveniently ignored. Just because you'd rather talk about its features doesn't mean there aren't other potentially legitimate concerns.
            Depends.

            Evolution of C into early C++? No.

            Evolution of C into C++20? I could agree.

            C++ originally was written like C with classes. Later you got many stuff, and i would say that smart pointers were true giant improvement. But originally? No way.

            The issue it can't be (or rather shouldn't be) used in kernel is because if you impose all sane coding style guides for C++ for kernel mode, you almost have C.

            Could you use class? Eh not really as big codebase uses struct and sounds sane to stick to it.

            Exceptions ? Hahaha, No.

            Function overloading? Due to name mangling sounds problematic.

            Another issue is that you can't quite use STL or Boost in kernel.

            Comment


            • Originally posted by arQon View Post
              has anyone with any nontrivial C experience, ever, NOT implemented fake OO/class support?
              Structs with function pointers are common to see. These are often used in a manner equivalent to what you can do with C++ and single or multiple inheritance. In other cases, they're modified on-the-fly -- such as to model a state machine -- which I would do in C++ using a struct or class with std::function<> members.

              The coolest thing I ever did with C was to use Boost's amazing preprocessor metaprogramming library to implement something like C++'s STL. It's more verbose, because you have to explicitly pass in a bundle of type information to every generic operation, but it scales in the same way (i.e. you can have nested containers and operate on them with generic algorithms).

              Originally posted by arQon View Post
              MI is something that in reality almost never solves more problems than it creates,
              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!).

              Originally posted by arQon View Post
              a language that doesn't have it is not in any way inherently unsuitable for general purpose,
              The counter-argument to multiple-inheritance you always see is that just about any MI hierarchy can conceivably be modeled as a single-inheritence hierarchy, but you incur a lot more complexity and fragility in doing so. It sounds counter-intuitive to argue that multiple-inheritance leads to simpler code, but this has exactly been my experience (okay, maybe not in the diamond pattern case, but if you really wanted to maintain abstraction over the implementation, then you'd have to use single-inheritance + some other mechanism, like pImpl).

              Originally posted by arQon View Post
              IIRC it was driven entirely by the *potential* for people to do really stupid things (hello operator overloading).
              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.

              Originally posted by arQon View Post
              ... would have made adopting C++ for the kernel a massive win even if those were explicitly called out as the only C++ "extensions" permitted
              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.

              Originally posted by arQon View Post
              - but the impression I got was that the decision was based solely against the ability to write code that was not just even more illegible than bad C, but simply couldn't be trusted to actually be sane *in isolation*, i.e. unless you also had the header file open etc.
              A lot of thought would need to go into whether & how various aspects of the language are applied, and maybe the majority of senior kernel devs were uncomfortable with that undertaking, given their relative lack of experience, and worried about the consequences of getting it wrong.

              You make a very good point about code needing to support some baseline level of readability without either a header file or a smart IDE that can show you type definitions & function prototypes. This is one of my main reservations about the auto keyword, which I use more sparingly than many.

              Originally posted by arQon View Post
              I still think it was a poor decision, but after some of the clown code I've seen over the years I can certainly sympathize with the concern.
              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.

              It would be very instructive to investigate how Haiku has negotiated all of these issues. And they were hardly the first. I think BeOS was the first big OS project to use ISO-C++.

              I attended a talk by some of their devs, back in the late 90's, but I knew a lot less about C++ and therefore didn't get so much out of that part of the presentation. I actually had a copy, and it ran amazingly on my quad-Pentium Pro. I was so impressed that it could even mount my Linux ext2 filesystems and had a bash shell.

              Originally posted by arQon View Post
              The fact that drivers, more than almost any other code, will be highly dependent on using "unsafe" is also something that never seems to be mentioned,
              LOL, good point.

              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.

              Comment


              • Originally posted by piotrj3 View Post
                Evolution of C into early C++? No.

                Evolution of C into C++20? I could agree.

                C++ originally was written like C with classes. Later you got many stuff, and i would say that smart pointers were true giant improvement. But originally? No way.
                Templates + STL is a big deal. Constructors + destructors are a big deal. Exceptions are a big deal. IMO, these are the 3 killer features of C++. Everything else you really need is implementable atop them, as Boost showed us, and they were all in C++98.

                That said, I really like the stuff added in C++11, and some of what's followed. First-class support for lamdas (instead of Boost's template hack) is a breath of fresh air.

                Originally posted by piotrj3 View Post
                The issue it can't be (or rather shouldn't be) used in kernel is because if you impose all sane coding style guides for C++ for kernel mode, you almost have C.
                I strongly disagree.
                • Constructors help cut down on uninitialized variables & reduce the verbosity of explicit initialization. Destructors help cut down on leaks, dangling references, and dangling locks.
                • The kernel would benefit a lot from generic algorithms. I'm sure they hacked something in C for doing that, but using C++ templates would make it safer and more concise.
                • You can have smart string & buffer classes that minimize the chance for buffer overruns.
                • Namespaces are a nice way to get concise names without all the manual prefixes that C programmers normally have to do.
                • I'm on the fence about operator overloading, but they could put some rules & clear guidelines around it, to make sure it's used sanely.

                The only major feature I really wouldn't use in the kernel is exceptions.

                Originally posted by piotrj3 View Post
                Function overloading? Due to name mangling sounds problematic.
                But you really want name mangling, to ensure type-safety. Even if you don't allow overloading, that's still a win, because it sanity-checks that the function signature a caller thinks it's using actually matches what it's linking against.

                Originally posted by piotrj3 View Post
                Another issue is that you can't quite use STL or Boost in kernel.
                Obviously. The kernel would have its own generic algorithms and data structures, which are customized to its needs, priorities, and constraints.

                It's all a moot point, but still kinda fun to contemplate.

                Comment


                • Originally posted by coder View Post
                  It sure would be interesting if Google used AWS instances...
                  How on Earth did I not think of that? I often feel stupid, but not this stupid.

                  Comment


                  • 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

                      Working...
                      X