The Rust team is pleased to present the release of Rust 1.13.0. Rust is a system programming language aimed at security, speed, and parallel code execution.
As usual, you can install Rust 1.13.0 from the corresponding page of the official site, as well as see the detailed list of changes in 1.13.0 on GitHub. This release includes 1448 patches.
It was a really hot time in Rust. We participated in three conferences in a row - RustConf , RustFest and Rust Belt Rust . It was great to see so many Rust lovers; We met with many for the first time! We thought a lot about the future, developed a plan for 2017 and created the tools our users needed .
And despite all this, we have collected a new release with a bunch of new cool chips.
Does release 1.13 include the long-awaited operator ?
, speeding up compilation, adding
Some features in Cargo and the standard library. This release also brings many small improvements to documentation and bug reports. This is the result of the work of many people, and they are not mentioned individually in the release notes.
This release contains important fixes for Cargo vulnerabilities. It depends on curl and openssl,
and they both recently published security updates. For details, see the corresponding announcements of curl 7.51.0 and OpenSSL 1.0.2j .
?
Rust purchased a new operator ?
. It makes the work with errors much more pleasant,
removing the visual noise. For example, we have the following code to read data from a file:
fn read_username_from_file() -> Result<String, io::Error> { let f = File::open("username.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } }
The code contains two paths that can fail with an error: opening a file and reading data from it. If one of them fails, we need to return the error from the read_username_from_file
function. To do this, we have to match
result of I / O operations. However, here we are simply forwarding an error to the call stack, and using match
is a constantly recurring template code. Its hard to read.
C ?
The above code will look like this:
fn read_username_from_file() -> Result<String, io::Error> { let mut f = File::open("username.txt")?; let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) }
?
It is an abbreviation for the whole match
expression, which we wrote above. In other words ?
takes Result
and, if it is Ok
, expands it and gives the nested value. If the Result
value is Err
?
returns control from current function. It is much easier to read: instead of the whole expression, we use the character "?". So we show that we handle the error in the standard way, passing it up through the stack.
Experienced Rust programmers can point out that this is the same as the try!
macro try!
,
available from Rust 1.0
. Indeed it is the same. Up to 1.13 read_username_from_file
could be implemented like this:
fn read_username_from_file() -> Result<String, io::Error> { let mut f = try!(File::open("username.txt")); let mut s = String::new(); try!(f.read_to_string(&mut s)); Ok(s) }
So why make extensions to the language if we already have a macro? For different reasons.
First, try!
confirmed its exceptional utility and is often used in the idiomatic Rust. It is used so often that it deserves a sweet syntax. This kind of evolution is one of the great advantages of a powerful macro system: the supposed extensions of the syntax of a language can be prototyped and tested without changing the language itself. In turn, a macro that has become extremely useful may indicate a lack of language capabilities. Such an evolution from try!
in ?
- a great example of this.
One of the reasons why try!
needs to be sugar-coated - this is what it is rather ugly in the case of multiple calls in a chain. Compare:
try!(try!(try!(foo()).bar()).baz())
a counterweight:
foo()?.bar()?.baz()?
The first fragment is quite difficult to read, and each error handling layer attributes
to the beginning of the expression call try!
. This requires excessive attention concentration for trivial error forwarding, and overshadows the main working code — calls to foo
, bar
and baz
. This type of call hooking with error handling is typical for situations like the builder
design pattern.
Finally, specialized syntax makes it easier to get errors — can we consider using ?
. And for code from macros it’s hard to make good mistakes. However, in this release, use error messages ?
not fully implemented yet.
Although this is a slight improvement in our experience ?
- a worthwhile improvement in ergonomics try!
. This is a good example of the consistent improvement in the quality of life that Rust will continue to receive.
More about ?
see RFC 243 .
We seriously focused on compiler performance. We already have some good news, but it will be even better in future releases.
Mark Simulacrum and Nick Cameron honed perf.rust-lang.org , our compiler performance tracking tool. He regularly runs rustc-benchmarks on dedicated hardware and tracks changes over time. This tool records the results of each compilation step and is used by developers to narrow the search range for commits that lead to performance degradation. This is an important part of our toolkit!
We can use it to take a look at the performance schedule for the 1.13 development period - from August 16 to September 29 (the graph is shown below). The schedule starts on August 25 and is filtered by several criteria - to exclude unreliable, incomplete or contradictory results. You can notice large reductions that are quantitatively reflected on the corresponding statistics page.
On September 1, there was a significant improvement - Niko turned on the normalized projections of the cache during the broadcast . This means that during the generation of LLVM IR, the compiler no longer recalculates specific instances of associated types at each location. Now it reuses previously calculated values. This optimization does not affect any code, but when certain type fragments are encountered, you will notice a difference. For example, for futures-rs , the build time for the debug version has been improved by 40% .
Another similar optimization is implemented by Michael Woerister. It speeds up the compilation of containers that export many embedded functions. If the function is marked as #[inline]
, the compiler stores its representation in MIR in rlib - in addition to the usual translation for use in the current container. Then it translates it in each container that calls the function. In retrospect, Michael made an obvious optimization: in some cases, the inline functions are intended only for other containers, so the compiler does not have to translate them in the container where they are declared. Of course, except when they are called there. This saves time on converting the function to LLVM IR and its processing by LLVM: optimization and code generation.
In some cases, this gives impressive results. The build time of ndarray is improved by 50% , and for (unpublished) winapi 0.3 , rustc now does not produce any machine code at all.
But wait, that's not all! Nick Nethercote also turned his attention to compiler performance , concentrating on profiling and micro-optimizations. This release already includes some of the fruits of his work , others are scheduled for 1.14.
See the release notes for details.
This release contains important fixes for Cargo vulnerabilities. It depends on curl and OpenSSL, and they both recently published security updates. For details, see the corresponding announcements of curl 7.51.0 and OpenSSL 1.0.2j .
Now you can use in-place type macros ( RFC 873 ) and apply attributes to operators ( RFC 16 ):
// , macro_rules! Tuple { { $A:ty,$B:ty } => { ($A, $B) } } let x: Tuple!(i32, i32) = (1, 2);
// #[allow(uppercase_variable)] let BAD_STYLE = List::new();
Built-in reset flags (inline drop flags) are removed. In the past, the compiler kept the "reset flag" in structures to understand whether to execute the destructor when structures moved in some execution paths. This increased the size of the structures, which prevented the transfer of types with destructors across the FFI boundary. For code that does not move structures only in part of the execution paths, this memory was wasted. At 1.12, MIR became the default translator - this was the foundation of many improvements, including the removal of these built-in reset flags . Now the reset flags are in the stack of those functions that need them.
In 1.13 there is a serious bug in code generation for ARM with a hardware implementation of floating point numbers. These are most of the ARM based platforms. Currently ARM is a platform of support level 2, so this bug does not block the release. Since 1.13 contains a security fix, we recommend ARM users to use beta versions 1.14. This thread will receive a fix for this problem soon.
Reflect
deprecated. See the explanation of what this means for parametricity in Rust.checked_abs
, wrapping_abs
and overflowing_abs
RefCell::try_borrow
and RefCell::try_borrow_mut
assert_ne!
and debug_assert_ne!
AsRef<[T]>
for std::slice::Iter
CoerceUnsized
for {Cell, RefCell, UnsafeCell}
Debug
for std::path::{Components,Iter}
char
SipHasher
outdated. Use DefaultHasher
.std::io::ErrorKind
See the release notes for details.
155 people contributed 1.13.0. Thank you very much!
Source: https://habr.com/ru/post/315192/
All Articles