Announcement

Collapse
No announcement yet.

Librsvg Continues Rust Conquest, Pulls In CSS Parsing Code From Mozilla Servo

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

  • #61
    Originally posted by jacob View Post
    I personally believe there are two kinds of coders: great coders who know what sorts of bugs can and do occur and will adopt methodologies and tools to help them deal with them, and then there are the l33t Real Programmers (tm) who are too dumb to even understand why their code is buggy.
    In other words:
    There are those who can hold a job as a programmer, and then there's college students who are self-proclaimed programmers and think this is relatable:

    Comment


    • #62
      Originally posted by ssokolow View Post
      I'll keep this brief, because the other have already said things I'd otherwise day.



      I'm pretty sure that it was here that either I or someone else has already pointed out that bootstrapping any self-hosting compiler is difficult and bootstrapping GCC from a non-GCC compiler is at least as involved as bootstrapping rustc from C++ via mrustc.

      As I understand it, GHC (the big name in Haskell compilers, which is also written in Haskell) also does something similar, having a special mode to emit a C bootstrapping shim which serves as an equivalent to mrustc for the purpose of porting to new platforms.

      Bootstrapping from somebody else's compiler easily enough to make it the standard approach for compilation just isn't part of the typical design specification for a self-hosting compiler.



      Yes. The comment you replied to was explicitly predicated on that understanding. Specifically, I said that the "C++ is drawing away the 'aid' of companies like Microsoft who want to legitimize whatever hacks they're already using in their own compilers" is the only reason C has remained as simple as it is when it's attained such adoption and ubiquity.



      See my above comment about GCC's "hilarious bootstrap issues".



      Now I know you're full of it, because Rust developers fear the prospect of becoming the next C#, design-wise, and work very hard to do just the opposite of what you describe...as you'd know if you hung out in the RFC discussions and pre-RFC discussions as I do.

      (eg. I was the guy who pointed out how my preferred choice out of the proposed syntaxes for inclusive ranges ( ..= ) was to the "less than or equal" operator ( <= ) as the exclusive range syntax ( .. ) was to the less than operator ( < )... and there was a lot of bikeshedding over whether Rust should even have an inclusive range syntax or whether it was acceptable to require everyone to deal with having to work around the special case of having to handle a range which includes the highest value a variable of that type can represent.)

      In fact, they take pride in being the language that doesn't embody the latest and greatest, but, instead, gave some overlooked good ideas from the 90s a second chance.
      What I always find funny in discussions like this is that the baby duck syndromers who fight tooth and nail to defend C++ always (and I mean always) fail to point out Rust's real shortcomings. All languages have them and Rust of course is no exception, including compared to C++. But I guess they are too busy cultivating denial and inventing lame excuses for C++'s godforsaken mess to actually learn something about Rust and be able to look at it with a real critical mind.

      So here are my personal Top 5 griefs about Rust in no particular order, free of charge ;-)
      1. To this day, stable Rust still doesn't have a "placement new" operator. Worse still, unless you use unsafe, all objects are allocated on the stack AND THEN moved to the heap if needed. Most of the time this is not a problem but in some cases, such as when allocating huge, statically sized objects, it can incur measurable overhead or even not work at all.
      2. If type T implements trait S, there is no safe and correct way to cast (for example) a Rc<T> as a Rc<dyn S>. This stood in my way a couple of times and it makes some operations (such as keeping a vector of pointers, for example) unnecessarily complicated. Some would say that it means that my code is probably poorly structured, I won't dispute that. In C++ you can do it in an unsafe way; in Rust it's just cumbersome.
      3. C interoperability. In the real world this is a must for any programming language. Rust puts up a valiant effort with bindgen & co., but in C++ it's truly seamless.
      4. Platform support. Rust's Tier1 includes basically Linux, Windows and MacOS on amd64 and i686, period. Even ARM is relegated to Tier2. C++ on the other hand can be used to develop for virtually any ISA and OS imaginable, including old 16-bit computers.
      5. IDE support. 'Nuff said.

      Comment


      • #63
        Originally posted by jacob View Post

        What I always find funny in discussions like this is that the baby duck syndromers who fight tooth and nail to defend C++ always (and I mean always) fail to point out Rust's real shortcomings. All languages have them and Rust of course is no exception, including compared to C++. But I guess they are too busy cultivating denial and inventing lame excuses for C++'s godforsaken mess to actually learn something about Rust and be able to look at it with a real critical mind.

        So here are my personal Top 5 griefs about Rust in no particular order, free of charge ;-)
        1. To this day, stable Rust still doesn't have a "placement new" operator. Worse still, unless you use unsafe, all objects are allocated on the stack AND THEN moved to the heap if needed. Most of the time this is not a problem but in some cases, such as when allocating huge, statically sized objects, it can incur measurable overhead or even not work at all.
        2. If type T implements trait S, there is no safe and correct way to cast (for example) a Rc<T> as a Rc<dyn S>. This stood in my way a couple of times and it makes some operations (such as keeping a vector of pointers, for example) unnecessarily complicated. Some would say that it means that my code is probably poorly structured, I won't dispute that. In C++ you can do it in an unsafe way; in Rust it's just cumbersome.
        3. C interoperability. In the real world this is a must for any programming language. Rust puts up a valiant effort with bindgen & co., but in C++ it's truly seamless.
        4. Platform support. Rust's Tier1 includes basically Linux, Windows and MacOS on amd64 and i686, period. Even ARM is relegated to Tier2. C++ on the other hand can be used to develop for virtually any ISA and OS imaginable, including old 16-bit computers.
        5. IDE support. 'Nuff said.
        When such a young language only has 5 major pain points (and one of them is IDE support), I'm thinking it's doing a pretty good job

        Fwiw I'm not terribly familiar with Rust and I don't expect it to be flawless at this point. But the idea behind it looks sound, the implementation will eventually get there. Not chasing for anything and everything at the same time is also something wise (I should know, I'm fighting this pretty much on every project I work on).

        Comment


        • #64
          Originally posted by jacob View Post
          [*]To this day, stable Rust still doesn't have a "placement new" operator. Worse still, unless you use unsafe, all objects are allocated on the stack AND THEN moved to the heap if needed. Most of the time this is not a problem but in some cases, such as when allocating huge, statically sized objects, it can incur measurable overhead or even not work at all.
          Yep. It would seem there was unstable support for that, which got removed as it wasn't sound and nothing replaced it so far. Luckily, I didn't need that, yet. Neither in rust, nor in C++ (we only recently switched to C++14 at work ).

          Am I correct to assume Box uses placement new?

          Originally posted by jacob View Post
          [*]If type T implements trait S, there is no safe and correct way to cast (for example) a Rc<T> as a Rc<dyn S>. This stood in my way a couple of times and it makes some operations (such as keeping a vector of pointers, for example) unnecessarily complicated. Some would say that it means that my code is probably poorly structured, I won't dispute that. In C++ you can do it in an unsafe way; in Rust it's just cumbersome.
          I think the most idiomatic way would be not passing around Rc<T> or Rc<dyn S> to your functions, but &T and &dyn S -- unless of course you want to transfer ownership. But usually that's not what was intended.

          What I've learnt from experimenting with rust in the last two years or so is the following: If it causes too much pain to beat my code through the compiler, then often my design is crap. C++ is a lot more forgiving here.

          Originally posted by jacob View Post
          [*]C interoperability. In the real world this is a must for any programming language. Rust puts up a valiant effort with bindgen & co., but in C++ it's truly seamless.
          I guess that is a two faced medal. For C++. As it needs to stay compatible, it's hard(er) to make changes to the language.

          Originally posted by jacob View Post
          [*]IDE support. 'Nuff said.
          About a year ago, I switched to CLion for both my rust and my C++ needs. And never looked back. CLion still struggles with the new async fn stuff, but the rest of the experience is really great. Apart from that, I've heard great things about rust-analyzer, an replacement for the existing language server rls. But I didn't try that, yet.
          Last edited by oleid; 13 November 2019, 09:16 PM.

          Comment


          • #65
            Originally posted by jacob View Post
            [*]Platform support. Rust's Tier1 includes basically Linux, Windows and MacOS on amd64 and i686, period. Even ARM is relegated to Tier2. C++ on the other hand can be used to develop for virtually any ISA and OS imaginable, including old 16-bit computers.[/LIST]
            Fair, but, at the same time, it's important to understand what Tier 1 [i]is[/].

            Specifically, Tier 1 involves having, modulo any catch-up skipping, each push being tested on their CI system by building, checking for correctness of the build, and then running a big test suite.

            Last I heard, they were having trouble finding a viably priced CI service that could offer geniune ARM servers to run CI on... let alone all the other Tier 2 platforms like MIPS, RISC-V, PowerPC, SPARC, etc.

            In fact, last I heard, it had reached the point where, if Microsoft weren't donating time on Azure, that much CI time would be quite expensive.
            Last edited by ssokolow; 13 November 2019, 10:35 PM.

            Comment


            • #66
              Originally posted by oleid View Post
              Am I correct to assume Box uses placement new?
              To my knowledge no, and that's a problem. Even if you want to create Box<[usize; 1000]> it will allocate 1000 integers on the stack, copy it to the heap and then give you a pointer. If you want Box<[usize; 1000000]> you can't, because the stack can't contain it during initialisation. At that point you have two options:
              1. use a Vec instead, which directly allocates in the heap, but if you do that you will incur more dynamic bounds checks; or
              2. use unsafe to allocate it on the heap manually.

              Originally posted by oleid View Post
              think the most idiomatic way would be not passing around Rc<T> or Rc<dyn S> to your functions, but &T and &dyn S -- unless of course you want to transfer ownership. But usually that's not what was intended.
              For function arguments of course, but the problem is if you create some Cars, some Buses and some Vans, all implement Vehicle and you want some data structure to contain them all.

              Originally posted by oleid View Post
              I guess that is a two faced medal. For C++. As it needs to stay compatible, it's hard(er) to make changes to the language.
              True. But still, when you need to interact with C, and in practice sometimes you really do, it's easier in C++ than in Rust.

              Originally posted by oleid View Post
              About a year ago, I switched to CLion for both my rust and my C++ needs. And never looked back. CLion still struggles with the new async fn stuff, but the rest of the experience is really great. Apart from that, I've heard great things about rust-analyzer, an replacement for the existing language server rls. But I didn't try that, yet.
              Personally I find that the need for a good IDE is much greater in Rust than in C++. Besides, rls integration is priceless. If one of Rust's main selling points is that it basically comes with a built-in powerful static code analyser, then running it implicitly during each build is great, but running it in the background as you type is even better

              I also confess that I haven't tried CLion for Rust, I always felt deterred by the fact that it implements its own parser and analyser instead of using rls, so it sounds like it's bound to always lag behind Rust's features. From what I tried, VSCode with the right add-ons provides probably the best Rust experience but it's limited by the fact that VSCode isn't really a full-blown IDE, more like the modern day equivalent of Emacs.

              Comment


              • #67
                Originally posted by ssokolow View Post

                Fair, but, at the same time, it's important to understand what Tier 1 [i]is[/].

                Specifically, Tier 1 involves having, modulo any catch-up skipping, each push being tested on their CI system by building, checking for correctness of the build, and then running a big test suite.

                Last I heard, they were having trouble finding a viably priced CI service that could offer geniune ARM servers to run CI on... let alone all the other Tier 2 platforms like MIPS, RISC-V, PowerPC, SPARC, etc.

                In fact, last I heard, it had reached the point where, if Microsoft weren't donating time on Azure, that much CI time would be quite expensive.
                That's certainly true but all the same, unless I'm mistaken Tier 1 is the only one where it's guaranteed that the compiler actually generates correct code. Tier 2 and Tier 3 are in the "it should work" category, for varying definitions of "should".
                Last edited by jacob; 14 November 2019, 12:40 AM.

                Comment


                • #68
                  Originally posted by jacob View Post

                  To my knowledge no, and that's a problem. Even if you want to create Box<[usize; 1000]> it will allocate 1000 integers on the stack, copy it to the heap and then give you a pointer. If you want Box<[usize; 1000000]> you can't, because the stack can't contain it during initialisation. At that point you have two options:
                  1. use a Vec instead, which directly allocates in the heap, but if you do that you will incur more dynamic bounds checks; or
                  2. use unsafe to allocate it on the heap manually.
                  You're right. This seems to sum up the current state :

                  It's common in game development to want fine-grained control of where values are allocated. This would commonly be used in object pools/ECS systems. Support for this used to exist, but was removed....


                  Originally posted by jacob View Post
                  For function arguments of course, but the problem is if you create some Cars, some Buses and some Vans, all implement Vehicle and you want some data structure to contain them all.

                  Sure, as I said, that only works if you don't own the stuff. If it makes sense in your case, storing Rc<dyn T> would probably be the way to go, but that depends on so many things it's hard to tell without seeing the source.

                  In any case : use only references for non-owning access, as it properly expresses that fact in the function signature and it's easy to swap Rc for Arc or Box without changing anything.

                  Originally posted by jacob View Post
                  True. But still, when you need to interact with C, and in practice sometimes you really do, it's easier in C++ than in Rust.
                  That for sure! I think it's safe to say that rust will never beat C++ here. Probably bindgen will get better, possibly someone invents something to automatically generate safe abstractions for many cases. But still.

                  Originally posted by jacob View Post
                  I always felt deterred by the fact that it implements its own parser and analyser instead of using rls, so it sounds like it's bound to always lag behind Rust's features.
                  I know how you feel. I've been there, too. I guess at some point, the 'official' analyzer will be better, but at least a year ago, nothing could beat CLion here. My trouble is : what to use, if not using CLion? I don't really like Vscode. It feels slow. And it's C++ story was patchwork, at least a year ago. I really liked Qt Creator for c++due to its nice Cmake integration. It has now language server support, I read. Maybe I'll try that with rust-analyzer once that matures.

                  Comment


                  • #69
                    Originally posted by jacob View Post
                    To my knowledge no, and that's a problem. Even if you want to create Box<[usize; 1000]> it will allocate 1000 integers on the stack, copy it to the heap and then give you a pointer. If you want Box<[usize; 1000000]> you can't, because the stack can't contain it during initialisation. At that point you have two options:
                    1. use a Vec instead, which directly allocates in the heap, but if you do that you will incur more dynamic bounds checks; or
                    2. use unsafe to allocate it on the heap manually.
                    I get your point, but I don't understand why it's an issue. If you've got a big array, use a `Vec`. If you need to optimize out bounds checks, use `*_unchecked()` methods. If you want to allocate memory manually, accept that it is by nature unsafe.

                    Originally posted by jacob
                    If type T implements trait S, there is no safe and correct way to cast (for example) a Rc<T> as a Rc<dyn S>. This stood in my way a couple of times and it makes some operations (such as keeping a vector of pointers, for example) unnecessarily complicated. Some would say that it means that my code is probably poorly structured, I won't dispute that. In C++ you can do it in an unsafe way; in Rust it's just cumbersome.
                    Code:
                    use std::rc::Rc;
                    
                    trait MyTrait {fn is_mytrait(&self) -> bool {true}}
                    struct MyStruct;
                    impl MyTrait for MyStruct {}
                    
                    fn main(){
                        let a = Rc::new(MyStruct);
                        println!("{:?}", (a as Rc<dyn MyTrait>).is_mytrait());
                    }
                    Seems straightforward enough to me.

                    Comment


                    • #70
                      Originally posted by oleid View Post
                      That for sure! I think it's safe to say that rust will never beat C++ here. Probably bindgen will get better, possibly someone invents something to automatically generate safe abstractions for many cases. But still.
                      In the ideal world, C shouldn't really be used directly from C++ (i.e not exception safe, no RAII mechanisms, doesn't follow same patterns, etc). So a binding is generally ideal. However these bindings just end up easier to make.

                      Basically since Rust is native and uses the same backend underneath, it would be so handy to merge it with a basic C compiler so it can understand C headers and call functions. Then it would be just as trivial as C++ to wrap within the lifetime of objects. I would love to see this happen, Rust is soo close to being able to replace C++ in a lot of usecases.

                      It is less portable than C, so Rust will never win here, but C++ exceptions alone are not entirely portable to all architectures. The fact that Rust doesn't use exceptions means that possibly it could be more portable than C++.

                      Comment

                      Working...
                      X