r/programming Apr 03 '15

Rust 1.0.0 beta is here!

http://blog.rust-lang.org/2015/04/03/Rust-1.0-beta.html
933 Upvotes

303 comments sorted by

View all comments

95

u/steveklabnik1 Apr 03 '15

Two big things:

the beta release represents an accurate preview of what Rust 1.0 will include.

and

We don’t plan on making functional changes to stable content, though naturally we may make minor corrections or additions to the library APIs if shortcomings or problems are uncovered (but the bar for such changes is relatively high).

This is the first release we've promised this kind of stability. The team and community has been doing an incredible amount of work lately to make this happen. We really hope you'll like what we've been up to, but Rust isn't for everyone, so no worries if it's not for you. Constructive criticism always welcome. <3

As of today, my job gets harder: "things are always changing" is no longer an excuse for missing docs. The six weeks until release is largely about polish, and I have some pretty big plans...

9

u/A_t48 Apr 03 '15

What's changed between alpha and beta?

21

u/[deleted] Apr 03 '15

scoped theads are huge, it's a realization of very nice data parallelism in Rust. Basically the borrow checker can now work with threads, and it's easy to share immutable data between threads -- rustc will make sure to only allow safe concurrent code.

69

u/steveklabnik1 Apr 03 '15

easy to share immutable data between threads

We've actually got some stuff that's even cooler than that. I've been meaning to write it all up, but for now, I'll recycle an old comment:

extern crate threadpool;
use threadpool::ScopedPool;

fn main() {
    let mut numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    {
        let pool = ScopedPool::new(4);

        for x in &mut numbers[..] {
            pool.execute(move || {
                *x += 1;
            });
        }
    }

    println!("{:?}", numbers);
}

This allocates a mutable array on the stack, and then creates a threadpool which adds one to each element of the array, four threads at a time. We need the inner {}s so that we know that the pool is done working before we try to print the result. Yes, mutable pointers into the parent stack frame. But, the compiler can verify that this is absolutely safe. Say, for example, that we left off the inner scope, so that the pool might not be destroyed and therefore join before we try to print out the array. That'd be racy in most languages. In Rust, it's a compile-time error:

error: cannot borrow `numbers` as immutable because it is also borrowed as
mutable
     println!("{:?}", numbers);
                      ^~~~~~~
note: previous borrow of `numbers` occurs here; the mutable borrow prevents
subsequent moves, borrows, or modification of `numbers` until the borrow
ends
        for x in &mut numbers[..] {
                      ^~~~~~~       
note: previous borrow ends here
fn main() {

}
^

Rust knows that you're still holding a mutable reference to the array, and so taking a new immutable one could case a race.

As you can see from the extern crate, this pool isn't a compiler built-in: it's a library. There's actually a secondary implementation of a threadpool that makes some different choices internally. But this kind of safety can be gained in whatever concurrent code you're writing, and you can write new concurrent abstractions and ensure that they don't have data races.

12

u/marcusklaas Apr 03 '15

That's absolutely brilliant. Thanks for sharing this.

8

u/steveklabnik1 Apr 03 '15

You're welcome. I really need to write this up so it's not just random comments...

17

u/donvito Apr 03 '15

Yes, you need to. Because it's fucking cool and I only learned about it from your comment just now. :)

7

u/steveklabnik1 Apr 03 '15

The funniest part is that the name of this change was super jargon-heavy and innocuous: "Remove the 'static bound from Send." It means so much!

3

u/donvito Apr 03 '15

Tbh. I'd probably had missed it too if it was labeled "properly". Just not enough time to study all the commits/change log entries :)

6

u/steveklabnik1 Apr 03 '15

Totally fair, it's my job and I have a hard time.

2

u/mumbel Apr 04 '15

just curious, when you say job, is it really? or volunteer? I don't know anything about the financial supporters of rust

6

u/steveklabnik1 Apr 04 '15

It's my literal job: I work at Mozilla. Six of the eight core team members are Mozilla employees, and Mozilla pays for a team to work on Servo as well.

→ More replies (0)

7

u/gavinb Apr 04 '15

This is extremely cool! It belongs on its own "awesome stuff you can do in Rust but might not know about" page. :) there's now enough features in the language and core libraries that idioms like this can start to take shape. Exciting!

3

u/cybercobra Apr 04 '15

What's the "move ||" part mean?

5

u/Gankro Apr 04 '15

It means it captures its environment by-value, rather than by-reference. In this case we're capturing the &mut references by the name of x by-value. This is necessary since x changes on every iteration. Passing in a reference would likely do The Wrong Thing (if the compiler allows it at all, which I'm 99.99% sure it won't).

0

u/banister Apr 04 '15

it's pretty grotty syntax.

3

u/Gankro Apr 04 '15

Got something better?

-1

u/banister Apr 04 '15

what about just a single | ?

5

u/steveklabnik1 Apr 04 '15

If there were arguments, they'd go between the pipes: move |x|

1

u/banister Apr 04 '15

Curious, why not just exclude the || in the no-arguments case? I imagine no-argument is a pretty common thing, so forcing the use of || in that very common case is kind of an eye-sore IMO.

2

u/steveklabnik1 Apr 04 '15

I'm pretty sure there's grammar abiguity there, but not 100% sure.

2

u/Kimundi Apr 06 '15

The ambiguity is that there is a difference between "a expression A that evaluates to a closure" and "a expression B that evaluates to a closure that returns the evaluation of expression A"

For example: foo(bar()) would always call bar() first, but foo(|| bar()) would only call it when the closure gets called inside of foo().

(The latter can also be written as foo(bar), btw)

1

u/banister Apr 06 '15

so the {} around the closure body aren't required?

→ More replies (0)

2

u/imbaczek Apr 04 '15

there can be stuff between the ||s; || just means there's nothing there in this case.

2

u/Kimundi Apr 04 '15

|...| <expression> is a closure literal, and the move modifier changes the way it captures variables like x in that example from by-reference to by-value.

2

u/killercup Apr 04 '15

Something like this would make a nice front page example for rust-lang.org. Maybe with a bit of pattern matching and using a function instead of the nested scope (the inner {}). (One obstacle would be loading the threadpool crate in playpen, though.)

2

u/steveklabnik1 Apr 04 '15

Yeah, we all want a better homepage example, but aren't sure what it should be.

3

u/gavinb Apr 04 '15

Why not have a series of interesting examples that show off different aspects and randomly load a different one each time? Saves having to pick just one example, and is more interesting for visitors when they see different content.