Rust 0.12.0 released
mail.mozilla.org
mail.mozilla.org
There's also been tons of progress toward the last features that are blocking the 1.0 release (http://blog.rust-lang.org/2014/09/15/Rust-1.0.html). The long-awaited work on dynamically-sized types is now partially complete, and the only two remaining big hurdles that I can think of are closure reform and trait coherence reform. Onward to stability!
Really odd that they went with M:N model - if the OS is fast at creating/destroying threads 1:1 is the best model for vast majority of apps.
Basically, in the effort to make the abstraction Just Work between 1:1 and N:M threading, we made green threads so heavyweight that they barely even qualified as green anymore. It's only by removing that abstraction that we could feasibly make them lightweight again.
Sorry! We're sensitive to your use case, but we just couldn't make it work.
I have had a problem learning Rust by example, the codebases I would like to read don't usually work with the latest Rust releases.
I don't really _do_ C++, but if I could talk to Rust from C++ maybe I could start hacking on their codebases.
Edit: I found the http://doc.rust-lang.org/green/index.html is this what you are referring to?
fn get_mut<'a>(&'a mut self) -> &'a mut T;
fn print<'a>(s: &'a str);
The 'a parts are the lifetime annotations.We used to have a single inference rule for when you didn't need to write the annotation. With RFC 39[1], we added two more. These two extra inference rules removed 87% of the existing annotations, giving you this instead:
fn get_mut(&mut self) -> &mut T;
fn print(s: &str);
This is a pretty huge readability win.1: https://github.com/rust-lang/rfcs/blob/master/active/0039-li...
The detailed release notes have a more, er, detailed explanation: https://github.com/rust-lang/rust/wiki/Doc-detailed-release-...
But to clarify, functions which take 2 or more reference inputs won't benefit from this, since the compiler can't determine which lifetime parameter to use, right?
Edit: Never mind, I RTFM. Turns out it can't benefit.
fn f<'a>(x: &'a SomeType) -> &'a OtherType
you can now write this: fn f(x: &SomeType) -> &OtherType
Same meaning, just more concise syntax. fn f<'a>(x: &'a SomeType) -> &'b OtherType
?(Or when it has a lifetime of `static`, which means the referent is stored in static memory and thus is alive for the whole program.)
- The community was very friendly, although my questions probably were more on the 'RTFM' side of things
- The rust compiler is amazing. The error messages it provides are clear and helpful, often including potential spelling corrections and/or repeating the part of the code that causes trouble, closing with a suggestion to fix that.
It's not quite magic, but really impressive and helped me a lot to get started. Being a Windows dev by day I do bemoan the fact that this platform is a bit .. behind, but I'm actively pursuing a sideproject based on rust (on Windows) atm.
I'm sure that Clang inspired the great error messages - it sets a very high bar for new compilers (and old - GCC is still catching up).
> Being a Windows dev by day I do bemoan the fact that this platform is a bit .. behind
I'm sure that once 1.0 is released there will be a greater effort to make the Windows experience more seamless. This will be extremely important if we want to convince more game developers to give Rust a go. Have you seen https://github.com/PistonDevelopers/VisualRust/?
That said, IDE support isn't exactly what I was referring to.
- you need to install mingw separately and there are lots of reports about conflicts with other software that might bundle a different version of mingw
- installing cargo is weird (so far .. I failed and don't use it)
And even with my first baby-steps (i.e. doing basically nothing of value) I discovered some limitations, one being that you cannot create a DLL that exports an unmangled entry point - for stdcall (other calling conventions don't have that issue and follow #[no_mangle] or #[export_name="foo"].
BUT that's really not a huge deal for me. Just a bumpy road at times.
I think soon should be a time to look at performance. Performance should be close to or better than C++ on average. We know about "the root of all evil". But, if there is going to be any large uptake from those using C++ currently (and I imagine a lot of those developers are concerned about performance, memory usage etc), Rust simply has to compete on performance as well.
Go in a way started that path. The whole "systems language" re-interpretation and all. But it never quite became the systems systems language. It can't quite eat C's and C++'s lunch figuratively speaking.
Rust might be able to do it. But regardless of concurrency, type safety and other features if it cannot be fast enough it will have a hard time.
The language has been designed from the ground up to compete on this level. Also note that Rust potentially has far greater room for compile time optimizations than C and C++, because the compiler knows far more about lifetimes and ownerships. This can be seen in one of the last items in the release notes:
> Stack usage has been optimized with LLVM lifetime annotations.
(Theoretically we can also leverage Rust's ownership rules to automatically generate aliasing information. When implemented this should be an across-the-board speed boost for all Rust code in existence, in a way that C and C++ compilers can only dream of.)
To be fair, there are also optimizations that C can do that Rust can't, often resulting from C's undefined behavior.
I'd like to see more benchmarking done between rust and C++ where there is a solution for each language that is idiomatic or safe while another solution optimizes for performance.
1. We haven't put in the time for the benchmarks game, because we're too busy working on the language. 2. IIRC, the C++ version uses GMP, and we don't, because licensing. You can install a package if you need GMP, but that doesn't work for the benchmarks game.
> I'd like to see more benchmarking done between rust and C++ where there is a solution for each language that is idiomatic or safe while another solution optimizes for performance.
Much of Rust's safety comes with no runtime overhead, but some of it does.
fyi
http://benchmarksgame.alioth.debian.org/u64/program.php?test...
Why doesn't that work for the benchmarks game?
> Much of Rust's safety comes with no runtime overhead, but some of it does.
I guess he'd like to find out how much overhead.
http://benchmarksgame.alioth.debian.org/u64/benchmark.php?te...
I agree with you, unless the language creators address this the language has much more chance to remain unused.
Rust is a new, experimental language and the support for SIMD is still in development, and we still don't have much in the way of data-parallel libraries. The type system has been expressly adjusted to allow for safe data-parallel libraries though, so they will appear.
Also, a few other points:
- Rust allows for opting in to unsafe code (with rules and overhead similar to C), which can be used for performance optimisations. Last time I checked, none of the Rust benchmark programs used any unsafe. (On the other hand, all of the C programs are effectively using `unsafe` code always)
- C is using highly optimised libraries; Rust has zero overhead FFI, and so can easily call into them, but is not for those benchmark (e.g. the pidigits one is just a benchmark of "are you using GMP?", if the Rust was written to use it, there is no reason it would be slower than C)
- The worst offender (reverse-complement) is apparently written without any thought of performance, e.g. it is doing formatted IO for each and every character it emits, rather than writing to an in-memory buffer and dumping that in one go like the C.
In summary, those benchmarks do not reflect the fundamental speeds of the languages, other than the suboptimal SIMD support in Rust.
All it takes is someone to write a wrapper around gmp providing those parts of the API and it will be less verbose and not require the `unsafe` everywhere.
Timing:
$ /usr/bin/gcc -pipe -Wall -O3 -fomit-frame-pointer -march=native pidigits.c -o pidigits.gcc_run -lgmp
$ time ./pidigits.gcc_run 10000 > /dev/null
real 0m0.980s
user 0m0.976s
sys 0m0.000s
$ rustc --opt-level=3 pidigits.rs -o pidigits.rust
$ time ./pidigits.rust 10000 > /dev/null
real 0m0.987s
user 0m0.984s
sys 0m0.000sCan Rust link dynamically?
$ ldd pidigits.rust
linux-vdso.so.1 (0x00007fff8b9e7000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f5c233be000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5c231ba000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5c22f9c000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5c22d86000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c229de000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5c2372b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5c226dc000)Thank you. But a lot of people wouldn't get so far. Therefore please do promote good examples of the fast code that do something real, like these benchmarks.
Do you prefer reading benchmarks over the textual documentation? (genuine question)
Fast and looking nice when solving something like a real problem. Benchmarks can demonstrate that. Manuals and references typically not.
They certainly can. The actual "specification" documents probably not, but guides and tutorials (like Rust offers) can and (some of them) do.
I believe Servo is your reference, but you definitely need to have a bit wider horizons than that. The small benchmarks are good representation of the rest of the world. And the good advertisement, once they are fast. Please don't ignore them.
Those small benchmarks are not good representations of the rest of the world; they are contrived and limited problems, with some fairly arbitrary rules about which languages/implementations are valid to include, e.g. PyPy is not allowed, and Java gets JIT warm-up time etc.
… that no one has contributed them.
> … with some fairly arbitrary rules about which languages/implementations are valid to include, e.g. PyPy is not allowed …
Hundreds of programming language implementations are not included! It would take more time than I choose to donate. Been there; done that.
http://benchmarksgame.alioth.debian.org/play.html#languagex
> … and Java gets JIT warm-up time etc.
Java does not get JIT warm-up time! Please stop making up misinformation!
> Java does not get JIT warm-up time! Please stop making up misinformation!
Oh, sorry! I must've been misremembering something someone told me. (Although, how does `Cold` differ from `Usual` there? It's not clear from the text what the difference is.)
Best not to become so confused: " Measurement is highly specific -- the time taken for this benchmark task, by this toy program, with this programming language implementation, with these options, on this computer, with these workloads."
> `Usual`
http://benchmarksgame.alioth.debian.org/play.html#measure
> `Cold`
http://benchmarksgame.alioth.debian.org/play.html#java
"Here are some additional (Intel® Q6600® quad-core) elapsed time measurements, taken after the Java programs started and before they exited:
In the first case (Cold), we simply started and measured the program 66 times; and then discarded the first measurement leaving 65 data points."
I didn't know that.
(Seems like a better way to test would be to allow anything, with three sets of numbers. One for "time from source to as far as you can go without input" (i.e. compilation time, loading the source into RAM, that sort of thing) "time from input to end of first run", one for "time for nth run", with n being high enough that the timing settles. So after any JITters are done, that sort of thing.)
Maybe by giving the gist of an RFC through an example or an high-level description before linking to it, because there are some RFCs a bit overwhelming I think, more theoritical than illustrated with examples.
[1] https://github.com/rust-lang/rust/wiki/Doc-detailed-release-...
(Because of the nightlies, I mean -- the language itself even I use!)
But really, is there any reason to have these "releases" that almost no ones uses, or is it just to have a concrete changelog every once in a while?
As we approach 1.0, these last few snapshot releases will become more and more valuable since the reduced frequency of breakage means that they will be more representative of the final language. The fact that people feel compelled to develop against nightlies is a bug, not a feature! :)
http://doc.rust-lang.org/guide.html
"The first thing we'll learn about are 'variable bindings.' They look like this:
let x = 5i;
"And so on: "let (x, y) = (1i, 2i); let x = 5i; x = 10i; "
I had to double check if the default (when the i is not written) is something else than int. It is confusing.
The TL;DR is this: not having a default type makes you consider which size to choose. This is generally good. But there are two good cases in which having a default helps a lot: examples and tests. Both of these are small, and don't really care about the details.
In real code, inference means you can often not get away with annotating numbers, because the type is inferred. But in these two cases, there often isn't something to do the inference.
Long ago, there was fallback, and then it was removed, and now we're considering putting it back. This is a great example of Rust's practicality and a scientific/empiric mindset to building the language.
I believe that everybody can invent as much red tape as he wants, the hard thing is making it concise and effective for the everyday use, not for the writers of compiler.
Digressing, were there any discussions about using var like in Swift (instead of let mut)? What is the rationale for not making that more minimalistic?
There were (I think it was somewhere on GitHub). One of the things `let mut` facilitates is:
fn main() {
let (i, mut j) = (10i, 10i);
j += 1;
println!("{}", (i, j));
}
I'm sure there are other applications for it too (such as in pattern matching). It just fits better into Rust.I was interested in the answer to this too. I found these which helped me understand:
Integers, on the other hand, are harder. You _probably_ want i32, even on 64 bit machines, but then an i32 can't index an array, so for integers used that way, you want a machine-sized integer.
Really? In C I use both doubles and floats all the time.
> i32 can't index an array
Why? Is it because Rust would use less than 32 bits for indexes on some platforms? And how should then the indexes for arrays be written?
You have really a hard job, when such basic things change?
But with integers, it's different. It's not so much that an i32 _can't_ index an array, but that it _might not be able to_. On a 64 bit machine, you could have a very large array that's bigger than an i32 in size.
No. Floats are OK for big storage, but for a lot of uses you want to make all the intermediate calculations in doubles and only when storing the results to convert to floats again. See
https://news.ycombinator.com/item?id=8434128
(at the moment top of the front page) where people have problem with Intel using 66 bits mantissa internally for the input of 53 bits (double!). You don't want to have partial results as floats unless you're doing graphics and simple calculations where you need much less bits. You'd would never like to calculate a bridge construction with floats, even if the needed parts would at the end be written with only 4 digits.
Regarding indexes for arrays, there are typical uses that should be recognized: if I write a[ 1 ] I'd like to be able to address the element 1. If I write a[ 0xffffffffffff ] it's also clear it's more than 32 bits.
This whole topic is very much still under discussion. While many want defaults, what they default to is still a question. And there's a sizable group that doesn't want any default at all.
There is little performance advantage to using a 32-bit float. Their precision is low enough that you can't do anything useful without risking the correctness of your program.
They are, like shorts, an artefact of the past. Unlike shorts, their limitations are not within the intuition of the average programmer, which leads to widespread abuse and bugs.
Kill them before it's too late.
People mentioned the cache efficiency gain with floats, and that is already relevant to rust. If in the future maybe rust could be used for GPGPU, then the difference between float and double often becomes even more dramatic. You definitely want to keep float support for this.
(Though it must be said that Rust doesn't actually have a 16-bit float type at all.)
Rust sometimes seems like the antithesis to BDFL. I quite like that they experiment, but I'm wondering how this will work out post 1.0.