Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Here's my suggestion that I strongly believe could help Rust's (or any platform's for that matter) adoption:

There should be a list of somewhat larger projects (similar to the sample apps for Cocoa https://developer.apple.com/library/mac/navigation/index.htm...) maintained by people who actually understand the language. For me, and I imagine a lot of other people, the hardest part about learning a new language/platform is getting from the stage where I understand the syntax and APIs to getting somewhat proficient with it and being able to make informed decisions about how things should be done in that language.

A lot of times, when I look at some open source projects to learn from, I'm left with the impression that the author might not have really understood what s/he's doing and that really increases my frustration with the platform. A list of canonical projects would prevent this.

I'm aware of Servo but I feel that Servo is a.) too large of a project for a Rust n00b to learn from b.) it's not always up to date WRT to the language version and the best practices.

Alternatively, this could also be a list of 3rd party projects blessed by the Rust people as good projects to learn from.

While it might seem like a waste of time, I feel like this would e.g. reduce the number of people needing help on IRC or the mailing list so it might actually save time.



I completely agree. 9 times out of 10 I can pick up a new language, understand the syntax, but how to idiomatically structure a project is a completely different thing. Most of the time I would rather have the latter than the former - I can pick up most syntax from its actual use.


> how to idiomatically structure a project is a completely different thing.

Agreed, and I plan on explicitly tackling this too. That'll come after Cargo is a bit more solid, however.


steveklabnik, along these same lines, I've come across the claim that things like map, reduce, fold, etc., are not idiomatic Rust. But nothing about why or why not that might be true. That kind of guidance would be valuable, especially since Rust borrows so many concepts from functional languages.


I will certainly say that Rust is young enough that idioms are still forming, so beware of those who say anything is strongly idiomatic. Except four spaces, no tabs. That's _incredibly_ so. ;)

But yes, as they develop, I'll be encouraging the use of idioms directly in the documentation. My years of Ruby make me a big believer in developing and following idioms.

Oh, one last thing about that: iterators are way better than explicit loops in Rust, because loops have to do bounds checking, but iterators don't. So generally, iterators are not just better stylistically, but also performance-wise too.


> because loops have to do bounds checking, but iterators don't.

They still have to check something to know when to stop iterating, though, don't they? You may have traded a bounds check for a dynamic dispatch or some "is done" check, but there's still some conditional logic each iteration isn't there?


Yes there is conditional logic, but normally only the minimum necessary.

The iteration protocol is just a trait:

  trait Iterator<A> {
      fn next(&mut self) -> Option<A>;
  }
That is, "an iterator" is an object that has a next method yielding an optional value, with a missing value indicating the end of iteration. This is conventionally used statically dispatched, and the next method will normally be inlined, so the compiler can optimise it well.

(In particular iterators over simple data structures like vectors optimise to the same code as the equivalent in C/C++, modulo one small bug where LLVM doesn't yet fully understand the nonnullability of Rust's references.)


pcwalton or someone else who understands the issue more deeply here, but my current understanding is this:

Imagine we want to print out every single element of a `Vec`, Rust's growable array type. Here's the code with a loop:

    fn main() {
        let v = vec!(1, 2, 3);

        for i in range(0, v.len()) {
            println!("Number {}", v.get(i));
        }
    }
This of course, has to check that it's only iterated the maximum number of times. The check I'm referring to, though, is in `v.get`. That has to do a bounds check on the array. If we use the iterator version...

    fn main() {
        let v = vec!(1, 2, 3);

        for i in v.iter() {
            println!("Number {}", i);
        }
    }
Now we get each element out of the vector. No more bounds check!


The other replies explained the situation, but for the curious here's Rust's basic code for slice iteration: https://github.com/rust-lang/rust/blob/master/src/libcore/sl... (unfortunately buried in some macros). `if self.ptr == self.end` is where the guarantee is made, then the offsets are done unsafely. The other branch in that function is optimized away statically.


Bounds checking is different from the conditional checks in something like a loop. It's the logic that prevents you from accessing memory that isn't yours. If you have an array arr of length 5 in Java, if you do arr[10] you get an IndexOutOfBoundsException because you're not allowed to do that. If you did the same thing in C, you might get some data which is unrelated to your array, or perhaps a segfault.

So when you you loop over an array, your loop conditional makes sure that your index hasn't indexed out of bounds, in addition to the bounds checking that is performed when actually indexing the array. So you in a sense pay a double price for the same assurance. (This is modulo compiler optimizations.)

Rust has to guarantee memory safety (I guess Java makes the same promise). This means that you have to have bounds checking for array indexing, lest you index out of bounds of some array and get killed by the operating system, if that memory happens to be outside of your process' "turf". You can't eliminate that in general (or; it's hecka hard), but you can probably encapsulate things like iterating over data structures like arrays, vet the code, and say that "this thing loops from 0 to the length of the array minus 1... I swear on my mother's future grave that it is safe to turn off bounds checking for array indexing here." (The way they do it in Rust may be more rigorous than this, for all I know!)


> I swear on my mother's future grave that it is safe to turn off bounds checking for array indexing here." (The way they do it in Rust may be more rigorous than this, for all I know!)

The hard part about doing that is that it's only safe if the array is guaranteed not to be mutated during the loop. Rust enforces this through its borrow checking system.


They're perfectly idiomatic operations on iterators, but they're not the one-and-only way to do things, sometimes you just need an imperative loop.

(That is, Rust borrows concepts from functional languages, but is not a deeply functional language itself.)


Thanks for the suggestion. Now that Rust is actually starting to get some 'somewhat larger projects,' I think this is a great idea. And after 1.0, that list will explode pretty shortly.


Fair enough. You probably want to make sure that you have something like this before people start writing larger projects in Rust but write them the same way they would write C++. Eventually, they would hit some wall and complain about Rust as whole even though it's not really Rust's fault.


Mozilla's pcwalton wrote and maintains sprocketnes, an NES emulator written in Rust, which seems like a good example of a practical project with a well-defined scope: https://github.com/pcwalton/sprocketnes




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: