Following its roadmap to Rust 2018, Rust 1.36's most awaited new feature is support for the Future
trait, which is the first step towards bringing async/await
to the language. Additionally, it backports non-lexical lifetimes (NLL) to improve the borrow checker, and introduces a new alloc
crate to enable the creation of memory allocation-dependent libraries that do not require std
.
Futures are supported in Rust through the Future
trait, whose core method, poll
, attempts to resolve the future. In case the final value is not yet ready, poll
will suspend the current task and wake it at a later time when it can poll
again. The polling task can specify a Waker
, which the Future
will use to wake it up. A Future
should never be polled after it resolved. This may produce panic, block indefinitely the calling task, or other kind of problems. Significantly, though, poll
is a safe
method and its implementation shall guarantee it does not corrupt memory under any conditions.
Non-lexical lifetimes, introduced in Rust 1.31 (Rust 2018), can now be used with Rust 2015 as well. With NLL supported in Rust 2015, the old borrow checker is closer to be removed from the language. To make this a safe transition, the new borrow checker will emit warnings wherever it encounters code that is accepted by the old borrow checker but not legal anymore when using the new one. Non-lexical lifetimes are a major improvement to the Rust borrow checker by making it take into account the actual lifetime of a variable without necessarily binding it to its lexical scope.
Another new stable feature in Rust 1.36 is the alloc
crate, which is the result of factoring the global memory allocator and all types depending on it out of the std
crate. Consequently, std
imports all of those types from alloc
and re-exports them to preserve compatibility. Likewise, any library crate that requires memory allocation can import alloc
directly and do not add a dependency on std
, which is quite a large crate and not necessarily available for all environments, e.g., embedded systems. This is an important step, says the Rust team, to make it possible to create a larger ecosystem of #![no_std]
libraries. It is important to notice that alloc
support has been stabilized only for library crates, meaning #![no_std]
binaries will still require nightly Rust to be allowed to use alloc
. To sum this up, you can create a #![no_std]
library that depends on the global memory allocator by using:
#![no_std]
extern crate alloc;
Rust 1.36 is also paving to way to removing mem::uninitialized
, which is now considered too dangerous to be left in the language, and replace its uses with the safer MaybeUninit<T>
. Until now, mem::uninitialized
was used to bypass Rust initialization checks to implement lazy allocation. The only catch is its use irremediably breaks Rust safety, since the compiler assumes those values are correctly initialized. The new MaybeUninit<T>
type will support the same kind of behaviour but it will require the programmer to explicitly express its intention of using the value, hopefully after correct initialization, by using .assume_init()
.
As a final note, Rust 1.36 sports a new implementation of HashMap<K,V>
that is faster on average and has lower memory overhead thanks to its use of the SwissTable design.