Announcement

Collapse
No announcement yet.

GNOME's SVG Rendering Library Migrating To Rust

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

  • #51
    Originally posted by Master5000 View Post

    Say what you will but Visual Studio C++ is king.
    Outside the corporate world? Nope. It’s not even standards-compliant.

    I wonder how Herb Sutter feels, with all his important contributions to language standardization, knowing his own employer is one of the tardy ones in actually implementing those standards...

    Comment


    • #52
      Originally posted by mmstick
      Additionally, Rust is able to optimize much farther than C++, for a variety of reasons I've outlined in prior posts.
      The only reason you've outlined is that rust's type system enforces constraints on the types of references that can exist to the same variable. These give rustc extra pointer aliasing information, which allows llvm to generate code with fewer memory accesses, which therefore runs faster. But to claim that this enables Rust to optimise much farther is absurd. First, the number of opportunities where this optimisation would be made in Rust but missed in C++ is tiny to start with (and even more so due to C++ strict aliasing rules). Second, both rustc and clang are built atop llvm, which being a powerful optimiser, would certainly be able to spot the missed optimisation by itself in many cases. Third, at runtime the cost of unnecessarily re-loading some memory back into a register when it hasn't changed will be negligible, since it would still be in L1 cache. And this is just one tiny factor which happens to be in Rust's favour; there are many more factors in favour of either. As one example, Rust would be slowed by any runtime bounds checks which couldn't be optimised out. Rust only claims to equal equivalent safe C++ code; if there were a huge difference in code generation between the two then this would only indicate something is very wrong.

      D uses garbage collection and it is not feasible to remove it. It also has the same issues as C++ in regards to integration with C codebases.
      All three languages have pretty minimal integration issues with C, though how Rust could integrate even better with C than a language backwards-compatible with it I cannot imagine. It's certainly never been a problem for me, and apparently it isn't one for GCC either (for example). So what issues specifically are you referring to?

      Agree about the GC, but that's essentially the only major problem, and work is supposedly ongoing to make it optional. So if D doesn't count, it's still the next closest thing.

      Not particularly related to the kind of mass refactoring that I'm referring to.
      Refactoring is not cited in any list of advantages that I can find. Again, what are you referring to?

      Rust features lifetimes, a borrowing and ownership model, ad-hoc polymorphism and generics powered by traits, lazy functional programming, a powerful procedural macro system, significantly superior error handling strategy, proper pattern matching, channels-based concurrency, an Internet-powered modular build system, and a cross-platform toolchain manager, and more.
      So Rust has different features to C++, rather than better features. I.e. none of these features are a proper replacement for my original example, which was polymorphism + inheritance.

      Namely, whereas C++ programmers must always be stuck in defensive programming practices and avoid optimizations that are particularly dangerous by standing 10 feet away from the line (ie: using shared_ptr when not needed), Rust programmers are able to comfortably toe the line and perform more excessive optimizations, safely.
      I'd be more convinced by an actual example.

      significantly superior error handling strategy
      C++1z recently got something similar to Option + Result, i.e. Rust's main error handling strategies. When used together with exceptions, I would argue C++ has superior error handling, because exceptions still have zero runtime overhead until triggered (compared to passing around results with attached error information), and code using exceptions often results in the cleanest syntax, but you can still use optional for simple cases where appropriate. In any case, it is a matter of personal opinion.
      Last edited by ⲣⲂaggins; 08 January 2017, 07:27 PM. Reason: s/Error/Result/

      Comment


      • #53
        Originally posted by ⲣⲂaggins View Post

        The only reason you've outlined is that rust's type system enforces constraints on the types of references that can exist to the same variable. These give rustc extra pointer aliasing information, which allows llvm to generate code with fewer memory accesses, which therefore runs faster. But to claim that this enables Rust to optimise much farther is absurd. First, the number of opportunities where this optimisation would be made in Rust but missed in C++ is tiny to start with (and even more so due to C++ strict aliasing rules). Second, both rustc and clang are built atop llvm, which being a powerful optimiser, would certainly be able to spot the missed optimisation by itself in many cases. Third, at runtime the cost of unnecessarily re-loading some memory back into a register when it hasn't changed will be negligible, since it would still be in L1 cache. And this is just one tiny factor which happens to be in Rust's favour; there are many more factors in favour of either. As one example, Rust would be slowed by any runtime bounds checks which couldn't be optimised out. Rust only claims to equal equivalent safe C++ code; if there were a huge difference in code generation between the two then this would only indicate something is very wrong.
        I can quote core Rust developers on this subject, and the discussion is not merely just about optimizations being performed by the compiler (irrelevant) but the programmer being able to leverage Rust's type system to perform more excessive optimizations, easily:

        Originally posted by Manishearth
        IMO Rust is a bit more extreme with that philosophy (zero cost abstractions). C++ has it as well, but I've seen Rust programs go to crazy lengths to avoid allocation or deep copies or reference counting. These costs are often in isolation perfectly fine, but your average Rust programmer will always be thinking of ways to eliminate them, because they can, and be safe about it.

        OTOH most modern C++ codebases I've worked with have heavy usage of shared_ptr or equivalent. Some do distinguish between thread-safe and non-thread-safe refcounting, but most don't. Or they have code that calls implicit copy assignment operators liberally triggering deep clones. This kind of attitude makes total sense in C++ land; a lot of it isn't preventable (some is) without becoming too worried about safety, but from a Rust POV it seems very callous. It is inconceivable to have an Arc being used if it's never being shared across threads. It's inconceivable to have extra clones (though during the initial phase of the learning curve folks do end up cloning more than they need). It's inconceivable to even use reference counting when you can just share things.

        My favorite example of this is that the Rust compiler has more lines of documentation referring to Rc ("reference counted") than it does core code. Almost all the uses of Rc in the core code are somewhat inevitable (when dealing with things like dependency graphs and such). There are maybe ten types in the compiler that get reference counted, and AFAICT all but two are not widely shared or used. Most of the things are instead stored on a varying set of intertwined context objects that have differing but known lifetimes. It gets pretty complex, since different kinds of variables will last for differing amounts of time (and this complexity is reflected in the lifetime annotations), but you can still deal with these things safely without any worry and folks do precisely that. I've seen shared_ptr being broken out for much less complex things in C++. For this extreme level of complexity I certainly wouldn't even try using regular pointers in C++.

        (Rc and Arc are just examples; there are many other examples of how certain "unnecessary" costs which are considered okay in C++ would be abhored in Rust)
        This topic has been beat to death again and again by Rust developers on Reddit and Hacker News.

        Originally posted by ⲣⲂaggins
        All three languages have pretty minimal integration issues with C, though how Rust could integrate even better with C than a language backwards-compatible with it I cannot imagine. It's certainly never been a problem for me, and apparently it isn't one for GCC either (for example). So what issues specifically are you referring to?
        C++ is not backwards compatible to C. In order to import a C++ library into a C application, you must export a C interface. There are many complications related to integrating C++ into a C codebase, and very little benefit to do so. Rust provides compelling advantages over C++, both in how easy it is to integrate and features/safety that is provided, and therefore GNOME has chosen Rust.

        Originally posted by ⲣⲂaggins
        Agree about the GC, but that's essentially the only major problem, and work is supposedly ongoing to make it optional. So if D doesn't count, it's still the next closest thing.
        There was a huge discussion thread on the topic of Rust vs. D that demonstrates that there is far more wrong with D than that alone. You have a split community with split implementations that's made worse by the garbage collection. By the time that work is done to supposedly fix the garbage collection, which I'm doubtful of, it will be too late -- er it already is too late because Rust is here, today, without a garbage collector.


        Originally posted by ⲣⲂaggins
        Refactoring is not cited in any list of advantages that I can find. Again, what are you referring to?
        You need to frequent Rust's Reddit thread if you want to see lower level topics discussed -- a lot of valuable information and highlights that are not readily displayed on the website or in documentation. can be found there. There are many advantages that aren't cited on the website. The type system that Rust provides makes it very simple to completely rip out and perform major restructuring of the source code. This makes it invaluable to open source software development.

        So Rust has different features to C++, rather than better features. I.e. none of these features are a proper replacement for my original example, which was polymorphism + inheritance.
        The evidence in favor of Rust is insurmountable on the feature front. C++ is an ancient technology, so you cannot say that an old language with decades of baggage is equal to or better than a language that released two years ago, featuring many of the more recent language theory discoveries. C++ doesn't even support basics like modules or proper macros, and what features it has gained in the last decade has been merely disappointing. Seeing the recent C++ announcement on upcoming features, I have even less faith than before that C++ will ever be able to reasonably catch up with any modern language.

        There are fatal flaws with C++'s class-based object-oriented programming. OOP in itself is very inefficient and unmodular. Rust encourages data-oriented designs, whereas C++'s OOP goes against the very nature of data-oriented programming. C++ leads to designing software that is not as powerful as the ad-hoc polymorphism that Rust is able to provide, which is similar to how Haskell operates. Inheritance is about to resolved with the inclusion of Associated Type Constructors which will provide a stable HKT-like interface to inheritance.

        Originally posted by ⲣⲂaggins
        I'd be more convinced by an actual example.
        See above for one example. I can track down more examples, but here's a good webpage that summarizes some of the discussions held on Rust's Reddit thread over the new years: https://brson.github.io/fireflowers/

        Here is also some more quotes:

        Originally posted by mozilla_kmc
        Oh yeah, also the Rust compiler knows which data structures are thread-safe and will complain if you try to share a thread-local structure. So for example, we have thread-local refcounting as well as atomic refcounting, whereas C++ shared_ptr has to assume multithreaded use and will always pay the performance cost of atomic ops.
        Originally posted by mozilla_kmc
        As others have said, Rust statically prevents bugs like iterator invalidation and data races that are still common in C++. I won't belabor that point, here are some other advantages though:

        Rust's enums and pattern matching are really great. I wrote an HTML5 parser and used nested match for the whole thing. I've used Boost.Variant before and C++ just can't compare.

        In Rust, moves are always a memcpy (at most), whereas C++ allows overloading the move constructor. One consequence is that Rust's Vec<T> can resize with realloc, whereas a std::vector<T> resize has to manually move the elements -- the ctors can even throw! So Rust's Vec<T> is a lot faster than std::vector<T> (or so I'm told -- I don't have the numbers handy). On the other hand, Rust will have a harder time supporting intrusive data structures.

        Rust also has more optimization potential due to stronger pointer aliasing rules. We don't expose them all to LLVM yet, though.

        Rust has traits, whereas C++ polymorphism is duck-typed. In Rust your generic stuff is typechecked before it's instantiated. I guess C++ is adding Concepts Lite eventually, but it's not part of "modern C++" as used today. It's also nice to write a 10,000 line generic library without putting the entire thing in header files.

        Rust has a much nicer macro system than C. It can't do everything that C++ templates can, but I find it far more pleasant in the common cases. Rust also supports compiler plugins for totally new syntax, but that's an unstable and implementation-dependent feature so I'm not sure you want to count it.

        Philosophically, you can't make a nice language by adding stuff to C for 40 years. At some point you have to start from a clean slate.
        Some important links

        - https://www.reddit.com/r/rust/commen...due_to_a_good/
        - https://www.reddit.com/r/rust/commen...f=search_posts
        -

        C++1z recently got something similar to Option + Result, i.e. Rust's main error handling strategies. When used together with exceptions, I would argue C++ has superior error handling, because exceptions still have zero runtime overhead until triggered (compared to passing around results with attached error information), and code using exceptions often results in the cleanest syntax, but you can still use optional for simple cases where appropriate. In any case, it is a matter of personal opinion.
        Rust supports exceptions too, but exceptions are not ideal for proper error handling and thus are strongly not recommended. Exceptions make the type system dishonest. It's a terrible escape hatch that does nothing more than complicates the program and any library that uses exceptions. The great thing about Rust's monadic error handling with algebraic types is that it is very convenient to perform unit testing, compile-time checks, and with crates like error-chain, it is possible to generate very detailed error messages.

        As for runtime costs, the compiler is able to mitigate this when it knows that certain options cannot happen.

        Comment


        • #54
          I began by addressing a few claims from across your earlier posts which I judge to be exaggerated, or in other cases untrue. Your most recent post contains some more:

          Originally posted by mmstick
          C++ is not backwards compatible to C.
          From https://en.wikipedia.org/wiki/Backward_compatibility at the time of writing
          Compiler backward compatibility may refer to the ability of a compiler of a newer version of the language to accept programs or data that worked under the previous version.
          This is mostly true for C --> C++ (not completely, C++ has stricter casting rules), but obviously not true for C --> Rust.

          There are many complications related to integrating C++ into a C codebase, and very little benefit to do so. Rust provides compelling advantages over C++, both in how easy it is to integrate
          This is in reply to "So what issues specifically are you referring to?", but you merely repeated the original claim without evidence.

          OOP in itself is very inefficient and unmodular.
          Sounds exactly like this was lifted from the start of https://en.wikipedia.org/wiki/Object...ming#Criticism and taken out of context. The criticism is against making OOP a core principle. It has nothing to say about using OOP features in multi-paradigm languages in situations where it makes sense. And since my original example was about exactly that (overriding a subset of a class's functionality by re-implementing it in a subclass can be very useful), this has no relevance. You appear to be dismissing any feature that is not (fully) supported in Rust.

          See above for one example. I can track down more examples, but here's a good webpage that summarizes some of the discussions held on Rust's Reddit thread over the new years: https://brson.github.io/fireflowers/
          A page of selected Reddit comments from Rust users, not containing any technical point in support of the following:

          Namely, whereas C++ programmers must always be stuck in defensive programming practices and avoid optimizations that are particularly dangerous by standing 10 feet away from the line (ie: using shared_ptr when not needed), Rust programmers are able to comfortably toe the line and perform more excessive optimizations, safely.
          Points by mozilla_kmc are very good though.

          Rust supports exceptions too, but exceptions are not ideal for proper error handling and thus are strongly not recommended. Exceptions make the type system dishonest. It's a terrible escape hatch that does nothing more than complicates the program and any library that uses exceptions.
          If so, then I couldn't find it in the documentation. There is also http://www.rust-compare.com/site/exceptions.html, which appears to say the opposite.
          C++ and Java both have exception throwing and handling capabilities, Rust does not. Instead Rust handles errors through its return type, commonly using Result<T, E>.

          Comment


          • #55
            Originally posted by ⲣⲂaggins View Post
            Sounds exactly like this was lifted from the start of https://en.wikipedia.org/wiki/Object...ming#Criticism and taken out of context. The criticism is against making OOP a core principle. It has nothing to say about using OOP features in multi-paradigm languages in situations where it makes sense. And since my original example was about exactly that (overriding a subset of a class's functionality by re-implementing it in a subclass can be very useful), this has no relevance. You appear to be dismissing any feature that is not (fully) supported in Rust.
            I have long been opposed to OOP even before Rust. Object-oriented designs incur many cache misses, made worse if you are using dynamic dispatch, and lead to data structures that are not cache-friendly. It is better to have software data-oriented rather than object-oriented, as data-oriented designs are memory-efficient (cache-friendly) and thus much faster. Rust's protocol-oriented programming paradigm very much encourages data-oriented designs so, hence Rust making it's way into many low level areas that were otherwise exclusive to C. I think it was a serious mistake for academia everywhere to push all their eggs into the OOP basket with Java and C++, which now has created generations of OOP programmers that cannot think in a data-oriented manner.

            - http://gamesfromwithin.com/data-oriented-design


            If so, then I couldn't find it in the documentation. There is also http://www.rust-compare.com/site/exceptions.html, which appears to say the opposite.
            [/QUOTE]

            It's not readily findable in the documentation because it's heavily recommended against. It will probably find it's way into the upcoming Rust book at that's in development at some point. The key functionality in question is catch_unwind and resume_unwind, which will soon have more additions that expand on the existing functionality and take advantage of the Carrier (?) trait.

            Comment

            Working...
            X