Announcement

Collapse
No announcement yet.

Fedora 38 Looks To Shift RPM To Sequoia, A Rust-Based OpenPGP Parser

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

  • #11
    Originally posted by lowflyer View Post

    The emphasis was on "cargo cult". It just means the "refs" are counted within the compiler.

    These are features that are there in C++ and a couple of other languages since decades. I am quite amused about the rustafaris. They really think they invented it.
    It is still very different from C++'s atomic reference counter.
    A lot of things used in rust are present before but rust group into one PL.

    All the references are checked at compile-time and guarantee the reference are always valid and non-null, and these references can be point to anywhere, either heap or stack or global variables.
    It also works for struct/enum that contains reference to other fields.
    To archive this "ref counting" in C++, you would have to make every field an atomic ref pointer which also requires heap allocation.

    Rust also checks for mutability rule to prevent multithreaded modification without synchronization such as mutex/read lock or use of atomic variables while permitting concurrent reading.

    Comment


    • #12
      Originally posted by lowflyer View Post

      The emphasis was on "cargo cult". It just means the "refs" are counted within the compiler.

      These are features that are there in C++ and a couple of other languages since decades. I am quite amused about the rustafaris. They really think they invented it.
      This. Rustafaris are the "Halo invented FPS" of refcounts.

      Comment


      • #13
        Originally posted by lowflyer View Post

        The emphasis was on "cargo cult". It just means the "refs" are counted within the compiler.

        These are features that are there in C++ and a couple of other languages since decades. I am quite amused about the rustafaris. They really think they invented it.
        The compiler doesn't do any recounting at all. What the compiler does is based on RAII enforced by a linear type system of sorts that doesn't have any counterpart in C++ in any shape or form.

        Now as for the rustaceans, they don't claim they invented it, in fact there is little in Rust that's really novel. RAII is obviously from C++, the borrow checking model and its associated type annotations come from Cyclone I believe, the Hindley-Milner type system is from ML, traits are from Haskell, async is originally from JavaScript, the declarative macros are loosely inspired by Lisp, the hybrid imperative/functional flavour of the language comes from Ocaml etc. What makes Rust a game changer is not any feature as such, it's the way these features are integrated in a nearly completely orthogonal way and form a coherent, robust language with very high performance and usable for low level code.

        The "cargo cult" is to be found among the schoolyard-level C++ fanboys. They believe that since "their" language has an inherently broken unique_ptr and a std::move that was introduced three years later as an afterthought (and doesn't really work), it's the last word in programming language design and the world has no business expecting anything better.

        Comment


        • #14
          Originally posted by jacob View Post

          The compiler doesn't do any recounting at all. What the compiler does is based on RAII enforced by a linear type system of sorts that doesn't have any counterpart in C++ in any shape or form.

          Now as for the rustaceans, they don't claim they invented it, in fact there is little in Rust that's really novel. RAII is obviously from C++, the borrow checking model and its associated type annotations come from Cyclone I believe, the Hindley-Milner type system is from ML, traits are from Haskell, async is originally from JavaScript, the declarative macros are loosely inspired by Lisp, the hybrid imperative/functional flavour of the language comes from Ocaml etc. What makes Rust a game changer is not any feature as such, it's the way these features are integrated in a nearly completely orthogonal way and form a coherent, robust language with very high performance and usable for low level code.

          The "cargo cult" is to be found among the schoolyard-level C++ fanboys. They believe that since "their" language has an inherently broken unique_ptr and a std::move that was introduced three years later as an afterthought (and doesn't really work), it's the last word in programming language design and the world has no business expecting anything better.
          OK I get it. You guys moved on from shitposting everywhere about rewriting everything in Rust to actually doing it yourselves because you realized your pleas fell on deaf ears. Why won't Rust find itself its own niche? Why does Rust have to be the only language to steal every language's job and want to eat everyone else's lunch?
          Last edited by rmoog; 01 December 2022, 08:14 AM.

          Comment


          • #15
            Someone should rewrite Rust's code generation in Rust.

            Comment


            • #16
              Originally posted by ClosedSource View Post
              Someone should rewrite Rust's code generation in Rust.
              There's actually a codegen called rustc_codegen_cranelift (https://github.com/bjorn3/rustc_codegen_cranelift) which uses the cranelift codegen developed by wasmtime written in Rust https://github.com/bytecodealliance/...main/cranelift

              Its main advantages is that it's very fast compared to LLVM/GCC codegen, so it is very suitable for debug builds.

              Comment


              • #17
                Well, first of all, it worked yay! Peeing on the rust-anthill stirred up the rustafarians. I rarely had so much "feedback" on a single post of mine...

                Originally posted by jacob View Post
                The compiler doesn't do any recounting at all. What the compiler does is based on RAII enforced by a linear type system of sorts that doesn't have any counterpart in C++ in any shape or form.
                Are you aware that you directly contradict your fellow rustafarian NobodyXu that says "All the references are checked at compile-time"

                You also contradict your own statement when you declare "RAII enforced by a linear type system of sorts that doesn't have any counterpart in C++ in any shape or form." and further down say "RAII is obviously from C++"

                Apart from that, what you're saying here sounds like "high-level-management-talk". You know, of somebody that doesn't have a clue. I'd rather like to see you explaining how rust-RAII is different from C++-RAII *in detail*.

                Originally posted by jacob View Post
                Now as for the rustaceans, they don't claim they invented it, in fact there is little in Rust that's really novel. RAII is obviously from C++, the borrow checking model and its associated type annotations come from Cyclone I believe, the Hindley-Milner type system is from ML, traits are from Haskell, async is originally from JavaScript, the declarative macros are loosely inspired by Lisp, the hybrid imperative/functional flavour of the language comes from Ocaml etc. What makes Rust a game changer is not any feature as such, it's the way these features are integrated in a nearly completely orthogonal way and form a coherent, robust language with very high performance and usable for low level code.
                I'm neither denying nor belittling anything of that. I think it was the correct thing to do. I would expect somebody inventing a new language to do their homework. The Rust engineers apparently did.

                What I don't like is the cult like behavior of the rustafarians (<-- derogative term for unreasonable rust fanboys). They sprinkle their sentences with buzzwords like "game changer", "coherent", "orthogonal", "robust", "linear", "integrated" and so on. Who do you guys want to impress? These words carry very little meaning if used without a significant amount of context. Are you even able to explain in detail what you mean with e.g. "coherent" and in which way it is different from other languages? We are mostly programmers here and we would understand it if you would just explain it. What do you fear?

                Originally posted by jacob View Post
                The "cargo cult" is to be found among the schoolyard-level C++ fanboys. They believe that since "their" language has an inherently broken unique_ptr and a std::move that was introduced three years later as an afterthought (and doesn't really work), it's the last word in programming language design and the world has no business expecting anything better.
                "schoolyard-level C++ fanboys" ??? Go, find me one!
                According to all these rustafarians, C++ is so extremely hard to learn that you will need at least 20 centimeters of beard before you can claim anything C++.

                I see rustafarians outdo each other with claims about "type safety" and other buzzwords. At each brief try with that language I come across the "unsafe" keyword. I can't help it, it feels like a joke. Religious sticking to the buzzwords while ignoring the failures is the definition of a "cargo cult"

                There are other languages out there that have tried and accomplished much but still failed in the end. (remember Ada) Rust may have potential. But it does not yet have merits. Cargo cults rarely help achieving that.

                Comment


                • #18
                  lowflyer Stop calling me "rustafarian", that's annoying.
                  It's almost as if you are there just to troll me.

                  I said reference is checked is compile time, but that is not the same as simple reference counting like std::shared_ptr or Arc.

                  It permits one alias only and there's also lifetime subtype and variance rules.

                  While lifetime isn't something completely new, it is clearly different from reference counting.

                  Comment


                  • #19
                    Originally posted by NobodyXu View Post
                    lowflyer Stop calling me "rustafarian", that's annoying.
                    It's almost as if you are there just to troll me.
                    Fair. You don't deserve the "rustafarian" tag, you're the "more sane" voice in support of rust. But I hope jacob gets the point. It was meant to be annoying. At least equally annoying as being called a "schoolyard-level C++ fanboy". The "trolling" was not intended.

                    Originally posted by NobodyXu View Post
                    I said reference is checked is compile time, but that is not the same as simple reference counting like std::shared_ptr or Arc.

                    It permits one alias only and there's also lifetime subtype and variance rules.

                    While lifetime isn't something completely new, it is clearly different from reference counting.
                    Let's leave the childish arguing about buzzwords.

                    "lifetime vs. reference counting" - One is compile time, one is runtime, they obviously can't be *the same*. But they're essentially resulting in the same thing: allocating and freeing resources. On a more abstract level, you could think of "lifetime" as "reference counting with a limit: max-n <= 1". Unlimited reference counting makes sense with real shared objects. (which you should have few of)

                    Taking up the example from the rust documentation about lifetime. As far as I can see it, this is *exactly* the same as in C++ and many other languages. Please explain why rust's implementation is superior to all the others. I hope it is not just because it is found on the holy rust-lang-org website?

                    There is that section in the rust documentation about "validating references with lifetimes". Every C++ compiler would vomit back at you when you try to write something similar. In C++ it's impossible to create a reference before you "know" the referred object. This example is outright crazy to a C++ developer. To me it looks like the classic straw-man argument: You let rust do something that is not even possible in C++, and then claim superiority because rust doesn't compile. Apparently rust requires a "borrow checker" to prevent something really stupid.

                    Educate me, what do I get wrong here? Rust needs the borrow checker because it separates "lifetime" from "type". C++ on the other hand has "lifetime" and "type" inherently welded together and therefore *does not need* a borrow checker.

                    Can you also elaborate on "lifetime subtype" and "variance rules"?

                    Comment


                    • #20
                      Originally posted by lowflyer View Post
                      "lifetime vs. reference counting" - One is compile time, one is runtime, they obviously can't be *the same*. But they're essentially resulting in the same thing: allocating and freeing resources. On a more abstract level, you could think of "lifetime" as "reference counting with a limit: max-n <= 1". Unlimited reference counting makes sense with real shared objects. (which you should have few of)
                      There's also mutability rule that prevents you from modifying one variable concurrently from multiple threads without synchronization.

                      For example, you cannot mutably borrow the same variable twice (create multiple alias), send them to two threads and have them modify it concurrently.
                      You would have to wrap that variable in Mutex/RwLock, then send the immutable reference, or use atomic.

                      This also enables an additional optimization called "no alias".
                      The rust compiler can guarantee that if you have a mutable reference, then it must be the only one that can access it until the reference is dropped.

                      It seems that C can emulate that using "restrict" and C++ can use "restrict" as a GNU extension, but C/C++ compiler does not seem to use them as clang implementation for this optimization turns out to be extremely buggy.

                      Rustc has attempted to switch on "noalias" optimization in LLVM for several times and it all got disabled soon after rolling out in nightly channel because some miscompilation in LLVM.

                      Originally posted by lowflyer View Post
                      Taking up the example from the rust documentation about lifetime. As far as I can see it, this is *exactly* the same as in C++ and many other languages. Please explain why rust's implementation is superior to all the others. I hope it is not just because it is found on the holy rust-lang-org website?
                      Originally posted by lowflyer View Post
                      There is that section in the rust documentation about "validating references with lifetimes". Every C++ compiler would vomit back at you when you try to write something similar. In C++ it's impossible to create a reference before you "know" the referred object. This example is outright crazy to a C++ developer. To me it looks like the classic straw-man argument: You let rust do something that is not even possible in C++, and then claim superiority because rust doesn't compile. Apparently rust requires a "borrow checker" to prevent something really stupid.
                      Well, that's the very simple example.
                      In real life code get much complicated than that.

                      One simple example that clang/clang++ might fail is holding a reference to a element in std::vector, resize std::vector and then access it again.
                      If you have a function "int& f(std::vector &v);` that takes vector and return a reference, then later resize the vector, I doubt C++ compiler can catch it.

                      A more complex example involves async function.
                      async in Rust is where multiple futures can be executed concurrently but not necessary in parallel.

                      In futures-util, there's a function called "try_join", which let's you execute two futures concurrently in one thread without the overhead of thread synchronization.
                      This also means that you can borrow local variables without using "Arc" (which is reference counting).

                      This is where the real fun starts.
                      Without borrow checking, it's probably very easy to get that wrong.

                      Another example would be scope spawning https://doc.rust-lang.org/std/thread/fn.scope.html

                      Using std::thread::scope, you can spawn multiple threads that borrows local variable while still guarantee there's no use-after-free.
                      You can wait on the thread handle and join them or get the thread id or do whatever with them, but you cannot leak them outside that function std::thread::scope.
                      That guarantees that before std::thread::scope returns, all thread spawned in the function, which could use local variables, are dropped and implicitly joined as RAII.

                      It also uses subtyping to ensure that the thread created would have a lifetime smaller than the parameter "s" given to the callback:L

                      Code:
                      pub fn scope<'env, F, T>(f: F) -> Twhere F: for<'scope> [URL="https://doc.rust-lang.org/std/ops/trait.FnOnce.html"]FnOnce[/URL](&'scope [URL="https://doc.rust-lang.org/std/thread/struct.Scope.html"]Scope[/URL]<'scope, 'env>) -> T,
                      
                      // Here is where subtyping occurs, it guarantees that the 'env must be a subtype of 'scope, meaning it must outlive 'scope,
                      // which is the same lifetime of Scope<'scope, 'env>.
                      //
                      // It ensures that this object cannot escape the callback `f` in function scope.
                      //                                              |
                      pub struct Scope<'scope, 'env: 'scope> { /* private fields */ }
                      
                      impl<'scope, 'env> Scope<'scope, 'env> {
                         // Infer lifetime 'scope to be same as lifetime of self (Scope<'scope, 'env>)
                         fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>​;
                      }
                      That literally would not work if lifetime works like reference counting.

                      Originally posted by lowflyer View Post
                      Educate me, what do I get wrong here? Rust needs the borrow checker because it separates "lifetime" from "type". C++ on the other hand has "lifetime" and "type" inherently welded together and therefore *does not need* a borrow checker.
                      C++ does not have lifetime.
                      On the contrary, rust embeds lifetime in the type.

                      For example:

                      Code:
                      struct S<T>(T);
                      In the struct declaration above, the lifetime of T is also embedded in S itself.

                      So if you create

                      Code:
                      let i = 1;
                      let s = S(&i);
                      Suppose that the variable "s" has a lifetime 's and variable i has a lifetime of 'i, then `'i: 's`, meaning that 'i must outlive 's
                      This is called subtyping where 'i is a subtype of 's.

                      Originally posted by lowflyer View Post
                      Can you also elaborate on "lifetime subtype" and "variance rules"?
                      This doc explains lifetime subtyping and variance rules https://doc.rust-lang.org/nomicon/subtyping.html

                      Comment

                      Working...
                      X