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

  • #31
    Originally posted by kpedersen View Post

    This same thing happens on Rust. Dereferencing a NULL pointer will also segfault that.
    Only if you explicitly mark your code block as unsafe and do raw pointer dereferencing. Then all bets are off and you are supposed to know what are you doing. Even in this case those unsafe blocks are easy to find when doing code review and troubleshooting memory issues.
    C++ allows a whole bunch of bugs undetected by the compiler and invisible until you hit them on production.

    Comment


    • #32
      Originally posted by oleid View Post

      You should have a look at assembler. Even more control at your finger tips
      I've already done with Intel 8051, but it was long ago.

      Comment


      • #33
        Originally posted by kpedersen View Post
        This same thing happens on Rust. Dereferencing a NULL pointer will also segfault that.
        It doesn't. You can't have a Box (equivalent of unique_ptr) to a non-allocated object. Null pointers can't happen in Rust (except in unsafe of course), they have to be wrapped in Option and you can't dereference them without somehow acknowledging the None case.

        Bottom line, it's impossible to write an equivalent piece of code in Rust. It wouldn't compile.

        Originally posted by kpedersen View Post
        (also, .at() should be preferred to []. Why is it that people are happy to bounds check in every other language but consistently opt for the unsafe raw access with C++?)
        .at() wouldn't save you here because the bounds of the vector are not exceeded. Another problem is that bounds checking shouldn't be an opt-in and a matter of syntax; the compiler should try to prove that the index is within bounds and thus a check is not needed (Rust tries to do that) or perform a check if needs be.

        Originally posted by kpedersen View Post
        C++'s RAII with smart pointers provides almost identical functionality to lifetimes.
        Most resolutely NOT. C++'s smart pointers provide very little in terms of safety above raw C pointers. Example:

        Code:
        void foo(int &a) {
                auto p = unique_ptr<int>(&a);
                a = 10;
                ....
        }
        Presto! You have one supposedly "unique" pointer to an object that's already also pointed to by a reference; both can be manipulated and passed around independently of each other. Plus it will give you a nice runtime error the moment p goes out of scope.

        Originally posted by kpedersen View Post
        Also, how would Rust's lifetimes really work when in the real world (i.e pointing to an X11 DISPLAY* or SDL_Surface* data?). If the underlying data gets wiped, then it still gets ripped out from under both C++'s and Rust's reference systems.
        Rust's lifetimes and borrow checker basically say who allocates and destroys what; they don't imply any runtime support. If your question is how would it work for something like SDL_Surface*, the answer is: very well. Check out Rust's SDL crate.

        Now of course calling into C from any language is inherently unsafe because the compiler has no way to ensure that the C code really does what its type declaration says. But code written in Rust can be made provably safe; code written in C++ can't.

        Comment


        • #34
          Originally posted by kpedersen View Post

          This same thing happens on Rust. Dereferencing a NULL pointer will also segfault that.
          You cannot dereference a bare pointer in _safe_ rust. (Which is, what you get by default). Of course you can use an unsafe {} block, which tells the compiler: "Trust me, I know what I'm doing". And then the compiler will let you dereference a C-style pointer.

          (also, .at() should be preferred to []. Why is it that people are happy to bounds check in every other language but consistently opt for the unsafe raw access with C++?)
          Not sure. Probably because it's faster. Or because .at() looks more alien than [] to them. In rust [] is bound-checked by default, i.e. for a vector type. You are advised to use iterators to safely access data and prevent bound checks for every element.

          But still, you have the issue of dangeling references in C++.


          C++'s RAII with smart pointers provides almost identical functionality to lifetimes.
          Yes, but std::shared_ptr is insanely expensive. Due to atomics. And even if you share it, you cannot be sure, that it gets modified in another thread. (which is, by the way, prevented in rust's type system i.e. when using Arc, see below).

          Of course there is unique_ptr. But you cannot share it (except when using references- but those can easily become invalid).

          I'm not saying that shared_ptr don't have their usage - an equivalent type exists in rust, too. It's called Arc (as in atomic ref counted). And it can safely be shared between threads. But there is _no_ equivalent to rust's Rc (ref counted, not atomic) in C++. That's quite cheap, but cannot be sent to other threads. Rust's type system forbids that. (as the trait Send is not implemented). Hopefully something similar will come to C++ via concepts.

          So no, smart pointers are not really an alternative to lifetimes. Lifetime checks of references only cost at compile time, smart pointers are paid at runtime. It's almost as if you where saying you could do garbage collection instead of the lifetime stuf.

          Originally posted by kpedersen View Post
          Also, how would Rust's lifetimes really work when in the real world (i.e pointing to an X11 DISPLAY* or SDL_Surface* data?). If the underlying data gets wiped, then it still gets ripped out from under both C++'s and Rust's reference systems.
          Access to foreign stuff like that is only possible in unsafe blocks or unsafe functions in any case. Usually, library authors (or crate authors in rust-speak) provide safe abstractions at the language barrier. As for how to handle that safely -- I guess you'd need to provide a concrete example to answer that. If X11 or SDL are owning that surface, they have every right to delete it. And usually, there is some signalling mechansim to find out about that. But that would be part of the documentation, not the API or type system. Sad state of affairs.
          Last edited by oleid; 12 November 2019, 07:18 PM.

          Comment


          • #35
            Originally posted by dremon_nl View Post
            Only if you explicitly mark your code block as unsafe and do raw pointer dereferencing.
            Same with C++.

            You can grep your code for [, ], *
            These lines are your explicitly marked unsafe code. You shouldn't need them in strict modern C++

            The only time you will need them is when utilising C libraries. Same as Rust.

            Originally posted by oleid View Post
            I'm not saying that shared_ptr don't have their usage - an equivalent type exists in rust, too. It's called Arc (as in atomic ref counted). And it can safely be shared between threads. But there is _no_ equivalent to rust's Rc (ref counted, not atomic) in C++.
            A custom smart pointer that does this would certainly not be hard to implement. To be fair, I have already implemented an observer_ptr<T> that does just this in my own projects. If it is NULL (the original object has gone out of scope), it throws an exception when accessed. Very handy for things like Player / Enemy targets.

            As for threads. Not even Rust is 100% safe. I don't think any language is going to solve this so that any old fool can mash data between threads in a safe manner. Whether a language is 60% safe or 40% safe, it will still crash in front of a client .

            Yes, Rust can do slightly more error / safety checking at compile time. However I am pretty sure with a smart linter (and ban raw pointers), this could be possible with C++ too to a large extent and a few annotations.

            Originally posted by oleid View Post
            Access to foreign stuff like that is only possible in unsafe blocks or unsafe functions in any case. Usually, library authors (or crate authors in rust-speak) provide safe abstractions at the language barrier. As for how to handle that safely -- I guess you'd need to provide a concrete example.
            This would possibly be my main reason for switching to Rust one day. C++ library developers churn the same old unsafe, raw pointer garbage out. This kind of infects projects with "unsafe-ness". A good example is Oracle's Database C++ API library. Its basically just C . However that certainly isn't the languages fault. That is luddites and legacy causing the issues.

            That said, just because others have done the work on the bindings; doesn't really add too much merit to a language. What happens once they lose interest and you have to maintain it all yourself at the end of the day. The same with C++; those safety abstractions are great, whilst they work and are maintained.
            Last edited by kpedersen; 12 November 2019, 07:27 PM.

            Comment


            • #36
              Originally posted by Volta View Post
              kpedersen schmidtbag uid313 jo-erlend

              Thank you for your replies. I was thinking about C++, but I started to learn C two months ago. I did take a look at Java as well, but I didn't understand a thing - I need to know what every thing means and the tutorial didn't explain the syntax and classes at the beginning. When comes to C I'm feeling I have a full control of what I am doing.
              Yes. C gives you full control, but it also _requires_ it and that's very important to keep in mind. It's like coming of age, you know, you turn 18 and you feel like the world has finally given you adulthood. In reality, this is when the world _expects_ you be adult and will no longer _allow_ you to be a child. I think we could say that C as a first language is to learn chemistry and physics before you learn magic and that's not a bad idea, at least for an adult.

              It will definitely teach you a great deal about all the other languages you mentioned and most others as well. Just remember that C is a four-letter word.

              Comment


              • #37
                Originally posted by kpedersen View Post

                Same with C++.

                You can grep your code for [, ], *
                These lines are your explicitly marked unsafe code. You shouldn't need them in strict modern C++
                [...]
                Oh come on. That's not true and you know it. You must forbid to use references as well. And then it's hard to do things in C++. Read this:

                https://alexgaynor.net/2019/apr/21/m...-wont-save-us/

                Originally posted by kpedersen View Post

                As for threads. Not even Rust is 100% safe. I don't think any language is going to solve this so that any old fool can mash data between threads in a safe manner. Whether a language is 60% safe or 40% safe, it will still crash in front of a client .
                Care to back your claim? I've yet to come across a data race in a rust program. You CANNOT (as in compiler forbids) share data unsafely between threads in rust. The type system takes care of that. The shared_ptr type (Arc in rust) is read-only, for example. There is, however, a function "make_mutable", which makes a copy, however, if there are other observers.

                IF you want to modify the data inside this Arc, you have to use e.g. an Arc<Mutex<T>>.

                In contrast to C++. There, everybody is allowed to modify the shared_ptr from other threads. And if it's const, then you simply cast it away.


                Originally posted by kpedersen View Post
                Yes, Rust can do slightly more error / safety checking at compile time. However I am pretty sure with a smart linter (and ban raw pointers), this could be possible with C++ too to a large extent and a few annotations.
                There is extensive static code analysis you can use for C++ -- let alone the runtime analysis provided by the sanitizers. But still they don't catch everything. And it's still easy to shoot into your foot in C++. I'm not saying it's not possible to write good code in C++. But it's harder than it should be. Or to quote Scott Meyers (I trust you know that name)

                Originally posted by ScottMeyers
                C++ is a large, intricate language with features that interact in complex and subtle ways, and I no longer trust myself to keep all the relevant facts in mind.
                If he - being the author of so many C++ books - doesn't know, $RANDOM_CPP_PROGRAMMING_DUDE probably doesn't know either.


                Originally posted by kpedersen View Post
                That said, just because others have done the work on the bindings; doesn't really add too much merit to a language. What happens once they lose interest and you have to maintain it all yourself at the end of the day.
                I guess in that case, you should either maintain your dependency yourself, switch to an alternative or rewrite the stuff in rust - like the librsvg author did. There are even people writing whole operating systems in rust, i.e. redox or tock.
                Last edited by oleid; 12 November 2019, 08:03 PM.

                Comment


                • #38
                  Originally posted by jacob View Post

                  Really? Let's try some strictly modern C++:
                  Code:
                  vector<unique_ptr<int>> v;
                  v.resize(100);
                  cout << *v[50];
                  => segmentation fault

                  Modern C++ is much better than old C++ but that's al it is. It's nothing like Rust at all.
                  Ever heard of a debugger?
                  Code:
                  Program received signal SIGSEGV, Segmentation fault.
                  main () at test.cpp:9
                  9           std::cout << *v[50] << '\n';
                  (gdb) p v[50]
                  $1 = std::unique_ptr<int> = {get() = 0x0}
                  (gdb)
                  How good is gdb or lldb with Rust?

                  Comment


                  • #39
                    Originally posted by kpedersen View Post
                    Why would I arbitrarily limit myself to less platforms when strictly modern C++ is basically Rust anyway?
                    Keep in mind that Rust is less than five years old. I wasn't around then, but I would imagine that C was in a similar position back in 1977.

                    Originally posted by kpedersen View Post
                    You might be feeling a bit confident about Rust's portability now because LLVM has done the hard work for WebAssembly support. But 20 years down the line when SnazzoPlatform comes out and LLVM is long in the tooth; I can guarantee that a C compiler will be the first to target that platform. Heck, I bet the C compiler will exist before that architecture is even fabricated.
                    There's nothing about Rust that requires llvm. It just happens to be a good base for a reference compiler.

                    Comment


                    • #40
                      Originally posted by kpedersen View Post

                      For me? Yes! PC, Android, Wii is just the initial platform list for our project. In the past we also supported the Flash VM via CrossBridge (Adobe's GCC based C++ compiler). We supported Emscripten (back then ASM.js) 5 years before Unity. I even wrote a Unity API clone (Mutiny) so that we could put one of our titles for ExxonMobil out without having to wait for those Unity deadbeats. There is a lot to be said for working light and flexible.

                      Why would I arbitrarily limit myself to less platforms when strictly modern C++ is basically Rust anyway?

                      You might be feeling a bit confident about Rust's portability now because LLVM has done the hard work for WebAssembly support. But 20 years down the line when SnazzoPlatform comes out and LLVM is long in the tooth; I can guarantee that a C compiler will be the first to target that platform. Heck, I bet the C compiler will exist before that architecture is even fabricated.

                      With that all said. Rust (being native and not requiring a massive sodding VM and runtime) is certainly pretty portable. More so than Google's Golang because it doesn't use a garbage collector. So is not actually the worst choice.
                      LLVM being long in the tooth. That's laughable. Right up there with Clang being long in the tooth, and I'm not even defending Rust.

                      Comment

                      Working...
                      X