Announcement

Collapse
No announcement yet.

Even Apple Is Interested In Migrating Their C Code To Rust

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

  • #61
    Originally posted by cynical View Post

    One of the main benefits of Java is not having to interact directly with hardware. If you are having to use JNI then yes you are now forgoing memory safety and entering the dangerous land of C, in which case an experienced and disciplined C developer is definitely going to do better than you..
    Well that is kind of the problem. Almost every Java project I have partaken in has involved the JNI. For example OpenGL, using high performance streaming middleware; Android JNI to access hardware. Unless you treat Java like a non-extensible scripting language (like Awk), you will need the JNI.

    Yes, you may not be interacting with the hardware directly; but someone has had to. Too many developers overlook this JNI usage for almost every project because they just grab a binding dependency. However as soon as they need to maintain it themselves (i.e the binding has become obsolete) then they completely lack the skill and manpower to do so and the project collapses.

    Based on my experience, I am personally of the opinion that writing bindings to connect Java to native libraries, is harder and more error prone than just using a native language for the whole project directly in the long run. This is not a common belief for many Java developers because they have yet to experience the joys of maintaining a binding. They usually just whine if the binding breaks and get someone else to do the hard work.

    (Obviously by Java I also include VB.NET and Csharp.NET in this since they are the same technology).

    Comment


    • #62
      Just want to ask the source of the image.

      Comment


      • #63
        Originally posted by Saurbh01Soni View Post
        Just want to ask the source of the image.
        The source of the image in the article ? I took the picture.
        Michael Larabel
        http://www.michaellarabel.com/

        Comment


        • #64
          Originally posted by Luke_Wolf View Post
          Those who say "OOP is a mistake" either misunderstand OOP and blame OOP for shitty programmers who also don't understand OOP existing or they learned to program in the 70s and 80s and are clinging as hard as they can to C to try to remain relevant.

          The irony being that OOP is an extraordinarily simple concept. All OOP really is is architecting your program to be a box of things that have adjectives and can verb each other, and this box of things is attempting to closely model real world objects, processes, or concepts. That's it. Nothing more. Nothing less. The rest is all implementation details, and things that make it easier to achieve creating said models.
          I would argue it's simpler than that. It's just passing the object you are working with as the first argument to every function.

          It's not true that thinking it's a mistake is a sign of not understanding OOP. I mean I don't hate OOP by any means, but there are great arguments against it. To me personally, the main problem is the "API explosion" you get with all these user defined types and methods. I'm a functional programmer who prefers lisp. You know what's nice about that? I can use the exact same functions with all my data types, because I am operating on simple data structures that use the same interfaces instead of re-inventing methods for each custom type.

          Before I learned Java, I didn't really understand why there was such a focus on heavy IDEs like Eclipse. Now I get it. It's because remembering the API for thousands of types is not possible, and autocomplete is a blessing there. In a functional language (or using a language like JS in a functional style), you can learn 50 functions and use those same tools everywhere, so writing in a simple text editor becomes feasible.

          Comment


          • #65
            Originally posted by cynical View Post

            I would argue it's simpler than that. It's just passing the object you are working with as the first argument to every function.

            It's not true that thinking it's a mistake is a sign of not understanding OOP. I mean I don't hate OOP by any means, but there are great arguments against it. To me personally, the main problem is the "API explosion" you get with all these user defined types and methods. I'm a functional programmer who prefers lisp. You know what's nice about that? I can use the exact same functions with all my data types, because I am operating on simple data structures that use the same interfaces instead of re-inventing methods for each custom type.

            Before I learned Java, I didn't really understand why there was such a focus on heavy IDEs like Eclipse. Now I get it. It's because remembering the API for thousands of types is not possible, and autocomplete is a blessing there. In a functional language (or using a language like JS in a functional style), you can learn 50 functions and use those same tools everywhere, so writing in a simple text editor becomes feasible.
            While I agree that making massive, overcomplicated piles of classes is overkill, you don't want to go too far in the direction of just using basic types either.

            I went through both phases and learned that lesson the hard way.

            I still have some old codebases where, while not as bad as it could have been, they define more classes than necessary.

            Likewise, I went through a phase where I was writing un-maintainable mazes of chained integer accessors using only primitive types. A custom data type or two fixed that up very nicely by adding some field names and/or methods.

            Absolutes are rarely the correct path and I like the Happy medium embodied by Rust.

            Type inference is allowed within methods, but you must specify the method signatures explicitly.

            Types implement various common traits so they share a familiar API, but things like String, OSString, and Path uphold different invariants despite all ultimately being single-element struct wrappers around Vec<u8>, so it's a compile-time error to mix them up without explicit conversion.

            Likewise, compile-time verification of units of measure is a good idea. meters + feet should be a compile-time error.

            Comment


            • #66
              Originally posted by ssokolow View Post

              While I agree that making massive, overcomplicated piles of classes is overkill, you don't want to go too far in the direction of just using basic types either.

              I went through both phases and learned that lesson the hard way.

              I still have some old codebases where, while not as bad as it could have been, they define more classes than necessary.

              Likewise, I went through a phase where I was writing un-maintainable mazes of chained integer accessors using only primitive types. A custom data type or two fixed that up very nicely by adding some field names and/or methods.

              Absolutes are rarely the correct path and I like the Happy medium embodied by Rust.
              No you misunderstand me. I don't mean the difference between using classes and using, say, arrays of ints to represent matrices or something like that. I'm all the way in favor of classes/objects over primitives, barring performance concerns that you might get with things like boxing. I mean the difference between the OOP world of having to define methods on all your data types instead of using common functions like map, reduce, filter, etc. Let me give you a more concrete example.

              Say I write a person class in Java, with fields for the name, address, occupation, etc. Well proper design here would dictate that I add accessor methods so that I'm not directly touching the fields, so I might have a getName(), getAddress(), etc. Adding unique getters to everything kind of sucks, so a lot of IDEs automate the process for you. What do you do in Clojure, by comparison?

              Keywords (think symbols, which are often used as fields) act as functions, so I can represent my person as either a map or a record, and then a "getter" is just a reference to the field.

              Ex:

              Code:
              (def person
              {:name "Bob"
              :age 30
              :occupation "Software Developer"})
              
              ;; to "get" age
              (:age person) ;; -> 30
              So I don't have to write all these strangely named custom accessors. Now for methods, instead of writing something like getDistanceFromWork(), and calling it using person.getDistanceFromWork(), I could just write a (get-distance loc1 loc2) procedure and then write something like (get-distance (:work person) (:home person)), and now my get-distance procedure is portable. It's not tied to a person type. I can use it in other arbitrary locations, like another part of my application where I want to get the distance between two restaurants that happen to be popular for my user. I don't need to write something like person.getDistanceFromFavorites() or something like that, I just use the procedure I wrote with different arguments, because my procedure is no longer tied to a particular datatype.

              And under the hood my function could be doing an API call to some third party service that allows me to convert an address from a string to a set of geographical coordinates before doing subtraction to find the distance. That procedure could be useful for calculating distance in many contexts, but if I attach it to a person type, I am severely restricting its utility. It totally kills code reuse. I have other criticisms too, but that one is the worst in my eyes. Every time I interact with some new class in Java I have to lookup documentation for how to use it based on its methods, rather than just writing my own procedures based on the data contained in the fields. It's fine for people who are used to just consuming APIs and don't mind constantly guessing/learning new method names, but if you are writing your own functions, it's nice to learn a few simple tools and use them over and over again instead.

              Comment


              • #67
                Originally posted by cynical View Post
                No you misunderstand me. I don't mean the difference between using classes and using, say, arrays of ints to represent matrices or something like that. I'm all the way in favor of classes/objects over primitives, barring performance concerns that you might get with things like boxing. I mean the difference between the OOP world of having to define methods on all your data types instead of using common functions like map, reduce, filter, etc. Let me give you a more concrete example.

                Say I write a person class in Java, with fields for the name, address, occupation, etc. Well proper design here would dictate that I add accessor methods so that I'm not directly touching the fields, so I might have a getName(), getAddress(), etc. Adding unique getters to everything kind of sucks, so a lot of IDEs automate the process for you. What do you do in Clojure, by comparison?
                Ahh, yeah. I'm very glad that Python having property meant that I never learned (and then had to unlearn) a habit of pre-emptively adding accessors Just in Case™.

                (If you're not familiar with it, property enables a member that was formerly a dumb variable to be replaced with a getter and optionally a setter and/or deleter without altering the external API.)

                Originally posted by cynical View Post
                So I don't have to write all these strangely named custom accessors. Now for methods, instead of writing something like getDistanceFromWork(), and calling it using person.getDistanceFromWork(), I could just write a (get-distance loc1 loc2) procedure and then write something like (get-distance (:work person) (:home person)), and now my get-distance procedure is portable. It's not tied to a person type. I can use it in other arbitrary locations, like another part of my application where I want to get the distance between two restaurants that happen to be popular for my user. I don't need to write something like person.getDistanceFromFavorites() or something like that, I just use the procedure I wrote with different arguments, because my procedure is no longer tied to a particular datatype.

                And under the hood my function could be doing an API call to some third party service that allows me to convert an address from a string to a set of geographical coordinates before doing subtraction to find the distance. That procedure could be useful for calculating distance in many contexts, but if I attach it to a person type, I am severely restricting its utility. It totally kills code reuse. I have other criticisms too, but that one is the worst in my eyes. Every time I interact with some new class in Java I have to lookup documentation for how to use it based on its methods, rather than just writing my own procedures based on the data contained in the fields. It's fine for people who are used to just consuming APIs and don't mind constantly guessing/learning new method names, but if you are writing your own functions, it's nice to learn a few simple tools and use them over and over again instead.
                It's a little more difficult to do as you describe in a language with strong static-typing guarantees. You either need to implement a standard API for type casting, coercion, or conversion or you need to implement your method directly on the types.

                Again, I like Rust's approach there. (eg. Either standard-library traits like IntoIterator and Eq are used to present a consistent, familiar interface that core language constructs can make use of, or support for reinterpreting a type is implemented via traits like Deref and AsRef. For example, functions that deal with paths take an argument of type AsRef<Path> argument and Path, PathBuf, and all the string types implement AsRef<Path>.)

                On the other hand, when Rust doesn't make something seamless, there's good reason. For example, you can't use a for loop directly on a string because you need to do a method call to specify what you want to iterate. (eg. Lines? Codepoints? Codepoint indices? Bytes? ...the grapheme cluster iterator method that gets added to strings when you import the relevant trait from a third-party crate?)

                Comment


                • #68
                  Originally posted by ssokolow View Post

                  Ahh, yeah. I'm very glad that Python having property meant that I never learned (and then had to unlearn) a habit of pre-emptively adding accessors Just in Case™.

                  (If you're not familiar with it, property enables a member that was formerly a dumb variable to be replaced with a getter and optionally a setter and/or deleter without altering the external API.)
                  Interesting. No, I didn't know the Python solution to that problem.

                  Originally posted by ssokolow View Post
                  It's a little more difficult to do as you describe in a language with strong static-typing guarantees. You either need to implement a standard API for type casting, coercion, or conversion or you need to implement your method directly on the types.

                  Again, I like Rust's approach there. (eg. Either standard-library traits like IntoIterator and Eq are used to present a consistent, familiar interface that core language constructs can make use of, or support for reinterpreting a type is implemented via traits like Deref and AsRef. For example, functions that deal with paths take an argument of type AsRef<Path> argument and Path, PathBuf, and all the string types implement AsRef<Path>.)

                  On the other hand, when Rust doesn't make something seamless, there's good reason. For example, you can't use a for loop directly on a string because you need to do a method call to specify what you want to iterate. (eg. Lines? Codepoints? Codepoint indices? Bytes? ...the grapheme cluster iterator method that gets added to strings when you import the relevant trait from a third-party crate?)
                  Right exactly. I favor dynamic languages but in a static language you would use interfaces/traits to do the something similar. Rust made some good choices there. If I were to code in that language I would prefer a style like this over OO:

                  Code:
                  fn main() {
                    let vector = (1..)
                        .filter(|x| x % 2 != 0)
                        .take(5)
                        .map(|x| x * x)
                        .collect::<Vec<usize>>();
                     println!("{:?}", vector);
                  }
                  I just like generic functions. One of my favorite things about Rust is how procedures automatically return the last expression as the result of a function. That's identical to lisp and it makes so much sense.

                  Comment


                  • #69
                    Originally posted by cynical View Post
                    Right exactly. I favor dynamic languages but in a static language you would use interfaces/traits to do the something similar. Rust made some good choices there. If I were to code in that language I would prefer a style like this over OO:
                    That's actually perfectly idiomatic.

                    In fact, trying to be too OO in Rust is going to cause you grief because some of the worst OO patterns don't play nicely with the borrow checker.

                    Originally posted by cynical View Post
                    I just like generic functions. One of my favorite things about Rust is how procedures automatically return the last expression as the result of a function. That's identical to lisp and it makes so much sense.
                    Agreed. There are so many situations where, even if you're writing in a more imperative style, having an expression-oriented language makes things so much cleaner.

                    Comment


                    • #70
                      Oh, as COVID rolls over the globe and economies everywhere begin to struggle, these overhyped infantile shithonrust kidiots would soon face far more interesting challenges than merely "let's rewrite X in Y language, because it cool buzzword, blah!" or so. Economies about to crash badly, maybe even bringing new "1929 era" on our heads, at which point business would be forced to count every penny and justify any expense, to stay, ahem, anyhow operational at all. Apple already had it hard, being forced to close factories in china and facing quite a batshit in terms of supply chains and so on.

                      Needless to say, all this "let's rewrite X in Y, because Y is, basically, cool and hyped buzzword" donquixotery brings very little of "added value" compared to expenses. So best idea for apple would obviously be to fire these donquixotes ASAP and consider spending money on something that brings some added value. And I'm sorry but security isn't like that. No matter what you do, anyhow large and complicated system just not going to be secure. And merely replacing one kind of vulns with another kinds of vulns is the best you can get, as long as software still being written by humans.

                      Comment

                      Working...
                      X