Live data from Hacker News

Rust vs C Pitfalls

garin.io

101–110 of 379 posts

Re: Rust vs C Pitfalls

#101
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)

Count me excited. I've always liked the book, but I've also found it fairly lacking in ways I'm not sure I completely understand, I can likely lend part of that to my relative inexperience with Rust and systems programming in general.

One I can note is that I really like the new sections. I've never quite liked that the current book is just a bunch of chapters all in a row. Not that that's necessarily bad in and of itself, but I do think the new way is better.

Re: Rust vs C Pitfalls

#102
post #101

Earlier quoted context omitted.

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)

Count me excited. I've always liked the book, but I've also found it fairly lacking in ways I'm not sure I completely understand, I can likely lend part of that to my relative inexperience with Rust and systems programming in general. One I can note is that I really like the new sections. I've never quite liked that the current book is just a bunch of chapters all in a row. Not that that's necessarily bad in and of i…

Thanks! If you do check it out, don't hesitate to file issues.

Re: Rust vs C Pitfalls

#103
post #88

Earlier quoted context omitted.

On similar note, why Rust over Go? If I look at everything I used to write in C, I'd say 80% is well suited for Go and the rest I would fallthrough to Rust for. For the stuff where having a GC and slightly less control is OK, I don't see why I would want to use Rust. Rust is just much more complex and I prefer to keep it simple stupid (KISS). Basically, Go is good for 90% of what I used to use Java for and 80% of wha…

I write libraries. In Go I can only write libraries for Go programs. In Rust I can write libraries for any program. i.e. Rust can easily produce static and dynamic libraries that are linkable with C programs and any language with a C FFI. I can write Rust code that works for programmers using C, C++, C#, D, Go, Swift, Python, PHP, Java, etc.

> In Go I can only write libraries for Go programs.

That's not true. It's quite simple to create a loadable shared object in go and call it using anything with a c ffi.

Re: Rust vs C Pitfalls

#104
post #101

Earlier quoted context omitted.

Count me excited. I've always liked the book, but I've also found it fairly lacking in ways I'm not sure I completely understand, I can likely lend part of that to my relative inexperience with Rust and systems programming in general. One I can note is that I really like the new sections. I've never quite liked that the current book is just a bunch of chapters all in a row. Not that that's necessarily bad in and of i…

Thanks! If you do check it out, don't hesitate to file issues.

How far along is the new documentation? Would it be better to read https://doc.rust-lang.org/book/ or the github.io page? Maybe both?

Re: Rust vs C Pitfalls

#105
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…

It's very rare that any programmer switches computer languages. You're probably going to retire as a c programmer. What are they going to teach in school? What are new systems programmers going to start with? I suspect it'll be rust and go, not c.

That's definitely not true. I've had the pleasure of working with many colleagues that have, and (since good Scala engineers are thin on the ground) my company will often hire good engineers who're interested in working with Scala. Heck - I myself have picked up Scala and Rust in the past couple of years.

Re: Rust vs C Pitfalls

#106
post #88

Earlier quoted context omitted.

On similar note, why Rust over Go? If I look at everything I used to write in C, I'd say 80% is well suited for Go and the rest I would fallthrough to Rust for. For the stuff where having a GC and slightly less control is OK, I don't see why I would want to use Rust. Rust is just much more complex and I prefer to keep it simple stupid (KISS). Basically, Go is good for 90% of what I used to use Java for and 80% of wha…

I write libraries. In Go I can only write libraries for Go programs. In Rust I can write libraries for any program. i.e. Rust can easily produce static and dynamic libraries that are linkable with C programs and any language with a C FFI. I can write Rust code that works for programmers using C, C++, C#, D, Go, Swift, Python, PHP, Java, etc.

You can do this with Go as well, and have been able to for a while now.

http://www.darkcoding.net/software/building-shared-libraries...

http://blog.ralch.com/tutorial/golang-sharing-libraries/

Re: Rust vs C Pitfalls

#107
post #75
post #38

Earlier quoted context omitted.

This is only because the Rust implementations are using particularly slow code paths, either because SIMD/AVX optimizations requires a nightly compiler, some optimizations would require unsafe code, or that other languages are using particularly hacky code that would never fly in real world software. For example, many of the Java/C/C++ benchmarks are using custom optimizations that should be illegal for the benchmark…

> Case in point, some are featuring custom hash maps that feature hashing algorithms that, while fast, would never be useful as they provide no protection against collisions. They are useful in this case, aren't they? Custom hash map implementation can be also useful in other scenarios. This is feature of the language that allow you to do that so it's not "illegal" to use it. If Rust doesn't allow you to do something…

I have wondered the same for a while now, and I hope someone familiar with Rust can explain it: in many of the benchmarks Go is faster and/or uses less memory despite the GC. Like you, I don't see much trickiness in the Go code.

Re: Rust vs C Pitfalls

#108

Earlier quoted context omitted.

I'm 19, I started out with Java, I switched to JavaScript for some time, I move on to Python for which most of my projects exist in and sometimes I use C when the job counts for it. I'm also a pretty big fan of PHP and a few other technologies that are very nice. To recap this has been my life as a programmer: Java -> JavaScript -> PHP -> Python/C/Assembly This dream that most people have made up about programmers no…

Yeah but you're just getting started. Talk to me after you've been paid to be a python developer for 20 years or whatever and tell me how interested you are in learning a new language. I play with a lot of languages but I've invested a lot of time into learning python and getting a nice python workflow going. It would take a lot for me to switch to another primary first language. I work at a tech company that's been…

I pick the best tool for the job. I'm using pything because right now I'm in a python shop. I'd like to go back to Java though as pythons asyncio is insane. The only reason I'm using pyhton is because the people inheriting my code will only know python.

What may look like "bah humbug I'll use X because I like it" may just be picking a language on concerns not limited to features. Looking at social concerns is important as well. Who is maintaining your code after you're gone? Company tooling for certain languages? Will I get fired for using it (AI winter)?

Lots of big questions

Re: Rust vs C Pitfalls

#109
post #87

Earlier quoted context omitted.

ripgrep is your proof. Go read the blog post Steve linked. If you still don't believe it, read the code. There's not that much of it. Then compare it with similar tools written in Go, like sift and the platinum searcher. The problem is, searching a file quickly is not as simple as you want to believe. If you show me a naive line by line approah, I'll show you an approach that is much faster but more complex. Top spee…

> If you show me a naive line by line approah, I'll show you an approach that is much faster but more complex. Of course, I did it myself many times. But this is NOT the point, I've already wrote it. The point is that I wrote naive approach in both languages and it's a lot faster in Go. Which is a reply to what OP wrote (don't forget where this discussion started). In this case this is the fact and I don't see any re…

> 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 memory. I ran the following:

    $ /usr/bin/time -v ./lossolo-go /tmp/OpenSubtitles2016.raw.sample.en the
    $ /usr/bin/time -v ./target/release/lossolo-rust /tmp/OpenSubtitles2016.raw.sample.en the
Both runs report 6,123,710 matching lines (out of 32,722,372 total lines). The corpus is ~1GB and can be downloaded here (266 MB compressed): http://burntsushi.net/stuff/OpenSubtitles2016.raw.sample.en.... --- My /tmp is a ramdisk, so the file is in cache and I'm therefore not benchmarking disk reads. My CPU is an Intel i7-6900K.

The Go program takes ~6.5 seconds and has a maximum heap usage of 7.7 MB. The Rust program takes ~4.2 seconds and has a maximum heap usage of 6 MB. (As measured by GNU time using `time -v`.)

---

IMO, both programs reflect "naive" solutions. The point of me doing this exercise is to show just how silly this is, because now we're going to optimize these programs, but we'll limit ourselves to smallish perturbations in order to put a reasonable bound on the task.

If I run the Go program through `perf record`, the top hotspot is runtime.mallocgc. Now, I happen to know from experience that Scanner.Text is going to allocate a new string while Scanner.Bytes will not. I also happen to know that the Go standard library `bytes` package recently got a nice optimization that makes bytes.Contains as fast as strings.Contains: https://github.com/golang/go/commit/44f1854c9dc82d8dba415ef1... --- Since reading into a Go `string` doesn't actually do any UTF-8 validation, we don't lose anything by switching to using raw bytes.

Knowing this, we can tweak the Go program to great effect: https://gist.github.com/anonymous/c98dc8f6be6d414ae3e7aa6931... --- Running the same command as above, we now get a time of ~2.3 seconds and a maximum heap usage of 1.6 MB. That's impressive.

Now let's see if we can tweak Rust, which is now twice as slow as the Go program. Running perf, it looks like there's an even split between allocation, searching and UTF-8 validation, with a bit more towards searching. Like the Go program, let's attack allocation. In this case, I happen to know that the `lines` method returns an iterator that yields `String` values, which implies that it's allocating a fresh `String` for every line, just like our Go program was. Can we get rid of that? The BufReader API provides a `read_line` method, which permits the caller to control the `String` allocation. If we use that, our Rust program is tweaked to this: https://gist.github.com/anonymous/a6cf1aa51bf8e26e9dda4c50b0... --- It's not quite as symmetrical as a change as we made to the Go program, but it's pretty straight-forward IMO. Running the same command as above, we now get a time of ~3.3 seconds and a maximum heap usage of 6 MB.

OK, so we're still slower than the Go program. Looking at the profile again, the time now seems split completely between searching and UTF-8 validation. The allocation doesn't show up at all any more.

Is this where you got stuck? The next step from here isn't straight-forward because getting rid of the UTF-8 validation isn't possible to do safely while still using the String/&str search APIs. Notably, Rust's standard library doesn't provide a way to search an `&[u8]` directly using optimized substring search routines. Even if you knew your input was valid UTF-8 before hand, there's no obvious place to insert an unsafe `from_utf8_unchecked` because the BufReader itself is in control of producing the string contents. (You could do this by switching to using `BufReader.read_until` and then transmuting the result into an &str, but that would require unsafe.)

Let's take a leap. Rust's regex library has a little known feature that it can actually search the contents of an &[u8]. Rust's regex library isn't part of the standard library, but it is maintained as an official crate by the Rust project. If you know all of this, then it's possible to tweak the Rust program just a bit more to regain the speed lost by UTF-8 checking: https://gist.github.com/anonymous/bfa42d4f86e03695f3c880aace... --- Running the same command as above once again, we now get a time of ~2.1 seconds and a maximum heap usage of 6.5 MB.

In sum, we've beaten Go in CPU time, but lost the Battle for Memory and the battle for obviousness. Beating Go required noticing the `read_until` API of BufReader and knowing that 1) Rust's regexes are fast and 2) they can search &[u8] directly. It's not entirely unreasonable, but to be fair, I've done this without explicitly using any unsafe or any C code.

None of this process was rocket science. Both the Go and Rust programs were initially significantly sub-optimal because of allocation, but after some light profiling, it was possible to speed up both programs quite a bit.

---

Compared to the naive solution, some of our search tools can be a lot faster. Performing the same query on the same corpus:

    ripgrep    1.13 seconds, 7.7 MB
    ripgrep    1.35 seconds, mmap
    GNU grep   1.73 seconds, 2.3 MB
    ag         1.80 seconds, mmap
    pt         6.41 seconds, mmap
    sift      50.21 seconds, 16.6 MB
The differences between real search tools and our naive solution actually aren't that big here. The reason why is because of your initial requirement that the query match lots of lines. Lots of matches results in a lot of overhead. If we change the query to a more common type of search that produces very few matches (e.g., `Sherlock Holmes`), then our best naive programs drop down to about ~1.4 seconds, but ripgrep drops to about 200 milliseconds.

From here, the next step would be stop parsing lines and start searching the entire buffer directly. (I hope to make even this task very easy by moving some of the searching code inside of ripgrep to an easy to use library.)

---

In sum, your litmus test essentially comes down to these trade offs:

- Rust provides a rich API for its String/&str types, which are guaranteed to be valid UTF-8.

- Rust lacks a rich substring search API in the standard library for Vec/&[u8] types. Because of this, efficient substring search using only the standard library has an unavoidable UTF-8 validation cost in safe code.

- Go doesn't do any kind of UTF-8 checking and provides mirrored substring search APIs between its `bytes` and `strings` packages.

- The actual performance of searching in both programs probably boils down to optimized SIMD algorithms. Therefore, once you get past the ability to search each line of a file with minimal allocation, you've basically hit a wall that's probably the same in most mainstream languages.

In my opinion, these trade offs strike me as something terribly specific, and it's probably not something that is usefully generalizable. More than that, in the naive case, Rust is doing you a good service by checking that your input is valid UTF-8, which is something that Go doesn't do. I think this could go either way, but I think it's uncontroversial that guaranteeing valid UTF-8 up front like this probably eliminates a few possibly subtle bugs. (I will say that my experience with text encoding in Go has been stellar though.)

Most importantly, both languages at least have a path to writing a very fast program, which is often what most folks end up caring about at the end of the day.

Re: Rust vs C Pitfalls

#110
post #43

Earlier quoted context omitted.

On similar note, why Rust over Go? If I look at everything I used to write in C, I'd say 80% is well suited for Go and the rest I would fallthrough to Rust for. For the stuff where having a GC and slightly less control is OK, I don't see why I would want to use Rust. Rust is just much more complex and I prefer to keep it simple stupid (KISS). Basically, Go is good for 90% of what I used to use Java for and 80% of wha…

For me this is pretty easy. It's about leadership. The leaders of Go foster an attitude of exclusiveness (just like a month ago they wanted to get rid of the Go subreddit in favor of a solely Google owned option of Google groups). The leaders of Rust are very receptive and helpful to new people. They are on IRC / Reddit and many other channels. I'd much rather invest my time into a truly open language and to me, that…

> (just like a month ago they wanted to get rid of the Go subreddit in favor of a solely Google owned option of Google groups)

Wow, really? Do you have a link to that discussion? That's wild.

Post reply on HN