Live data from Hacker News

Rust vs C Pitfalls

garin.io

191–200 of 379 posts

Re: Rust vs C Pitfalls

#191
post #176

Earlier quoted context omitted.

> Meanwhile, C code from the mid-80s still compiles with modern compilers, often without any changes whatsoever, and without any feature gates. You say that like it's a good thing that with C, you can ignore 30 years of progress in software development. Colour me unconvinced.

If the software does what you want, being able to run on 30 years worth of hardware with just a recompile is a good thing. At the end of the day, it's what the software does that's important.

And the plan is that you'll be able to do the same with Rust; the more rapid release strategy doesn't affect that at all.

What the rapid releases do affect is the rate at which new releases of libraries stop working on older compilers, which absolutely has to do with ignoring progress.

Re: Rust vs C Pitfalls

#192

Earlier quoted context omitted.

Agree that Rust lacks something comparable to NumPy for numeric work. Rust does have lots of numeric crates. Too many. I took a look at matrix multiply functions recently.(See [1], below "Here is what the Rust compiler actually does", for some notes on the effectiveness of Rust's subscript checking optimization.) "algebloat" wouldn't compile on stable. "matrixmultiply" is all unsafe code, with C-type raw pointers. "n…

Did you not check out `nalgebra`? https://docs.rs/nalgebra/0.10.1/nalgebra/

That's mostly a library for small vectors for 3D graphics and such. (I once did one of those myself, for C++.[1]) There's some support for 2D matrices in "nalgebra", but with heavy use of "unsafe".[2]

Every matrix package I've seen so far in Rust turns off subscript checking with unsafe code.

[1] http://graphics.stanford.edu/courses/cs148-10-summer/algebra... [2] https://docs.rs/crate/nalgebra/0.10.1/source/src/linalg/deco...

Re: Rust vs C Pitfalls

#193

Earlier quoted context omitted.

C is a very small and very portable language. Rust is not. I wondering why people bother comparing them at all.

C has also been relatively stable for the last 25 years or so. Rust changes every 6 weeks. Yes, the language is supposedly not undergoing breaking changes without strict deprecation and feature-gating. However, as new features are added to the language, libraries are usually updated to leverage them, and suddenly you are also forced to keep up with that rapid release cadence to ensure your project still builds. Meanw…

The problem with your concept is that C does not offer an official standard library and compiler suite, so you're trying to compare the C spec to the Rust standard library + compiler.

The actual Rust API has changed very little since the 1.0 release. All the changes that have occurred have been mere additions to the language -- nothing breaking. Hence why the 1.0 release was termed as a 1.0 release. There won't be anything happening that causes breakage until a 2.0 release.

You'll find that C compiler and library development is also rapid like Rust. There's new versions of LLVM/Clang and GCC being released on a regular basis. There are constant updates to musl and glibc. These changes tend to break far more often than Rust, which is developed in Rust and can be guaranteed to be much safer.

That Rust is being openly developed on GitHub with a significant number of developers, with an official compiler + library + doc + comprehensive suite of resources collectively being maintained, that's a significant incentive to work with Rust. There's a solid RFC process to prevent anything silly from entering the language. No random decisions by random people -- it takes a lot of convincing to add a new feature to Rust.

Re: Rust vs C Pitfalls

#194

Earlier quoted context omitted.

> The point is that I wrote naive approach in both languages and it's a lot faster in Go. I tried your challenge, and the first data point I uncovered contradicts this. Here is the source code of both programs: https://gist.github.com/anonymous/f01fc324ba8cccd690551caa43... --- The Rust program doesn't use unsafe, doesn't explicitly use C code, is shorter than the Go program, faster in terms of CPU time and uses less…

woah, amazing comment. I usually just a silent reader on hacker news, but this comment urge me to create an account. I think lossolo just want a flamewar. He already has opinion which you cannot easly change. So any futher discussion after this comment will be pointless. EDIT: and how can you have time to write this? I just usually close the browser tab when this situation occurs...

> I think lossolo just want a flamewar. He already has opinion which you cannot easly change. So any futher discussion after this comment will be pointless.

My opinion in this case is empirically checked. I am not saying this to start flame war, I am just showing my observations in particular example. I can also say that Rust regex implementation eats Go regex implementation by magnitudes (performance wise) and it will also be true and I am not looking for any flame war in this case also. I am only sharing my experience that I've backed up with proofs (code + perf results) for that particular use case. This is a factual discussion, I don't agree it's pointless.

Re: Rust vs C Pitfalls

#195
post #76

Earlier quoted context omitted.

http://blog.burntsushi.net/ripgrep/ There are only seven instances of unsafe: https://github.com/BurntSushi/ripgrep/search?q=unsafe&type=C... Four of them are related to calling libc/kernel32 functions, which need unsafe to be called. One is due to using a memory map, which needs unsafe to be called. Only two are actual unsafe rust functions. That's a "real-world" example though, you're asking for a more specific imp…

I told you NO unsafe code. Use only standard library, no third party tools. I have posted Go implementation to Rust magicians (it's just simple buffered reader, you do not need to be Go wizard to write it, any beginner can write it) and I've asked for Rust solution on Rust IRC channel because it was slower than easy Go solution, what I found out it's impossible to do it more efficient in Rust using standard library w…

> no third party tools

This is a tricky requirement. The standard libraries of both languages use a crap ton of unsafe code. You might end up just asking for a comparison of which standard library is bigger.

But at the end of the day, both languages have perfectly standard buffered readers (https://doc.rust-lang.org/std/io/struct.BufReader.html), shouldn't a simple search like this compile to the exact same code?

Re: Rust vs C Pitfalls

#196

Earlier quoted context omitted.

Your Rust program corresponds to my second Rust program. Your Go program is not what I would expect. A bufio.Scanner is the idiomatic (and naive) way to read lines in Go. But this is immaterial. Your results are consistent with mine. They aren't different. I just included more analysis and more programs to provide proper context to this challenge of yours.

I gave you naive solution, now lets see amateurish solution (someone totally new to both languages) Rust 4.6s Go 3.1s http://pastebin.com/r6K22Dt2 EDIT: Using grep 0.6s Then I have installed rigrep and... Using ripgrep 0.4s Really nice burntsushi. I am surprised by those (ripgrep) results compared to grep.

Seems I can't reply to your other comment, so I'll reply here. How can you say that my naive implementation is not naive? What is not naive about it? It's very naive. It's basically the same naive code that you were writing, but in actual idiomatic Rust with the linting issues fixed.

Using a `lines()` approach is naive because that allocates owned heap-allocated strings. An optimal, non-naive solution would not use heap allocation for buffering lines but use a stack-allocated array. That alone would bring significant speedup versus the line approach.

As for ripgrep, it's a pretty comprehensive application that makes use of SIMD/AVX so it's only natural that it's fast.

Re: Rust vs C Pitfalls

#197

Earlier quoted context omitted.

Did you not check out `nalgebra`? https://docs.rs/nalgebra/0.10.1/nalgebra/

That's mostly a library for small vectors for 3D graphics and such. (I once did one of those myself, for C++.[1]) There's some support for 2D matrices in "nalgebra", but with heavy use of "unsafe".[2] Every matrix package I've seen so far in Rust turns off subscript checking with unsafe code. [1] http://graphics.stanford.edu/courses/cs148-10-summer/algebra... [2] https://docs.rs/crate/nalgebra/0.10.1/source/src/linal…

Is there a problem with doing that with unsafe code? You have to remember that unsafe doesn't mean unsafe in Rust. If a developer is choosing to use the unsafe keyword, it's merely telling the compiler that they know what they are doing and what they are doing is safe. One shouldn't automatically infer that unsafe code is bad or negative. It doesn't deserve the negative stigmatism that it's given.

Re: Rust vs C Pitfalls

#198
post #4

Earlier quoted context omitted.

Well, I can't speak for tooling or productivity comparison to C/C++, but Rust has one of the best programming language documentations I have ever had the pleasure of reading [1]. [1] https://doc.rust-lang.org/stable/book/

Thank you! Carol and I are working on the second edition, you can read what we have so far here: http://rust-lang.github.io/book/ (I think it's even better, but I'm biased)

I'm enjoying the new write-up on ownership/references/borrowing! It reads more like an fascinating reading on PL concept than a language-specific manual. Great work!

Re: Rust vs C Pitfalls

#199
post #13

The kind of safety guarantees Rust provides are, in my opinion, insufficient justification for experienced developers to move from C or C++. Rust has other features that make it generally superior in certain (many) contexts. The safety is a nice "add-on" effect, I suppose, but my view is that constantly hyping safety as the biggest selling point is missing a mark.

I completely agree. The biggest reason I haven't seriously tried Rust yet is because, despite all the vocal pro-Rust opinions we've all been inundated lately, I struggle to name a single interesting thing about the language apart from "safety". I wish the Rust evangelists would come to terms with the fact that to many developers memory safety is not a particularly important concern (for many different and often very…

I see a lot of folks talking about this, but I live in a Rust bubble. From my POV a lot of the folks using Rust use it for primary reasons other than memory safety; many could afford to use python or something and get away with it. I suspect there are fewer blog posts about this, however.

I'll take a shot at some of the advantages:

Algebraic datatypes: Seriously. These are amazing. C++ has them with Boost's variant (and now std::variant), but they're awkward to use, making them somewhat a niche instead of the very central place they take in Rust programming. Till now ADTs were mostly the domain of functional languages, so I'm very happy that Swift and Rust giving them first class support and making them essential.

ADTs in Rust work with the enum keyword:

    enum Shape {
        Rectangle(Point, Point),
        Circle(Point, u32)
    }
    let some_shape = Circle(Point::new(1, 2), 5);
    match some_shape { // like switch, but with pattern matching
        Rectangle(p1, p2) => println!("Rect from {} to {}", p1, p2),
        Circle(p, radius) => println!("Circle at {} with radius {}", p, r)
    }
An enum is essentially an "or" type; i.e. "a Shape is a Rectangle (X)OR a Circle". You are forced to handle this fact when you access this data -- if you try to access the stuff inside some_shape, you must match (or use a method that does this for you), and the match must be exhaustive (cover all cases). This is how null works in Rust -- if you want to say something is nullable, you use `Option` -- `Some(T)` for when it's there and `None` for when it's null. You're forced to check for the none case if you want to be able to get to the inner data. You can call `.unwrap()`, but internally that's a method that just does a match and panics in the error case.

Traits: I mention this elsewhere in the thread, but Rust metaprogramming via generics cannot and will never beat C++ TMP's level of expressivity. Rust is going to get procedural macros which make it easier to fill in that gap of metaprogramming in a less hacky way, but if you just compare generics and templates then templates can do a lot more. However, that's not necessarily a good thing. The way templates are structured; they basically get "monomorphized" at something akin to parse time. This means that the error messages can be atrocious, and an API can never be self-documenting since you have to explain what kinds of types can be passed in. On the other hand, in Rust, if you get a function from a library you can pretend that it's a black box. The error messages will never mention the contents of the box. You can adequately figure out how to not make the compiler error out by looking at the type signature. The way Rust traits work is that you first define them:

    trait Frob {
        fn frob(&self, frobbee: &str);
    }
Then you implement them:

    impl Frob for SomeType {
        fn from(&self, frobbee: &str) { println!("{} frobs {}", self, frobbee) }
    }
Now, you can write functions (or types, or methods, or whatever) which accept these:

    fn frob_something_10x(frobber: T, frobbee: &str) {
        for _ in 1..10 {
            frobber.frob(frobbee)
        }
    }
If I did not have the `T: Frob` bound, I would not be allowed to write this method; the compiler would say that type `T` doesn't have a frob method, and I'd be forced to add a bound that gives it one. If a library user passed the wrong type to the function, the compiler will tell them that their type doesn't implement Frob, at which point they can add an implementation or use a different type or whatever. It's a very nice, clear API separation which leads to clear error messages and makes it easier to figure out what kinds of types to use. It also means that in the autogenerated docs I can just click on the trait to find out what types I can feed to the function -- in C++ many codebases have their own bespoke "trait" system using template specialization but it won't work with the docs and still lends itself to rabbit-hole-y error messages.

Moving: I personally find the lack of copy/move constructors and default construction to be very nice. In Rust, uninitialized types aren't a thing; initialization is always explicit. Copies are just copies, moves are also just copies, and moving is the default (except for POD types). There's no unknown overhead to deal with when I push to a vector, for example. Move-by-default and affine types IMO make it very easy to think about the program.

Re: Rust vs C Pitfalls

#200
post #2

If you're fighting, you've lost. The way to convert everyone to Rust you need to be better the the competition. Not just better as in "look at my features that will make your code safer". People may see the value but think "I get on just fine without the borrow checker so it isn't too important". You need to be far better then the replacement by providing the following: * Great Tooling ( IDEs ) * Great Libraries ( Ev…

> If you're fighting, you've lost. I don't really get this attitude, it means that nothing new will ever overcome anything that's been established. > Anything that can be done easily in C or C++ will need to be easier in Rust for everyone to move You don't even need folks to move from C. Rust has had lots of success when it comes to folks completely new to systems programming learning it through Rust. Predominantly p…

I'm currently trying to learn Rust, but if my motivation were "I need a fast language and don't want to deal with safety issues", I'd use Java. It's plenty fast (especially compared to something like Ruby!), the ecosystem is huge and tooling is extremely mature.
Post reply on HN