Skip to content

Rust 1.30 #281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 25, 2018
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
362 changes: 362 additions & 0 deletions _posts/2018-10-25-Rust-1.30.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,362 @@
---
layout: post
title: "Announcing Rust 1.30"
author: The Rust Core Team
---

The Rust team is happy to announce a new version of Rust, 1.30.0. Rust is a
systems programming language focused on safety, speed, and concurrency.

If you have a previous version of Rust installed via rustup, getting Rust
1.30.0 is as easy as:

```bash
$ rustup update stable
```

If you don't have it already, you can [get `rustup`][install] from the
appropriate page on our website, and check out the [detailed release notes for
1.30.0][notes] on GitHub.

[install]: https://www.rust-lang.org/install.html
[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1300-2018-10-25

## What's in 1.30.0 stable

Rust 1.30 is an exciting release with a number of features. On Monday, expect another
blog post asking you to check out Rust 1.31's beta; Rust 1.31 will be the first release
of "Rust 2018." For more on that concept, please see our previous post
["What is Rust 2018"](https://blog.rust-lang.org/2018/07/27/what-is-rust-2018.html).

## Procedural Macros

Way back in [Rust 1.15], we announced the ability to define "custom derives." For example,
with `serde_json`, you could

```rust
#[derive(Serialize, Deserialize, Debug)]
struct Pet {
name: String,
}
```

And convert a `Pet` to and from JSON because `serde_json` defined `Serialize` and
`Deserialize` in a procedural macro.

Rust expands on this by adding the ability to define two other kinds of
advanced macros, "attribute-like procedrual macros" and "function-like
procedural macros."

Attribute-like macros are similar to custom derive macros, but instead of generating code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wording nit: attribute macros are not "-like" attributes, they are attributes.

(While function-like macros are obviously not functions, so the "-like" suffix is justified there.)

for only the `#[derive]` attribute, they allow you to create new, custom attributes of
your own. They're also more flexible: derive only works for structs and enums, but
attributes can go on other places, like functions. As an example of using an
attribute-like macro, you might have something like this when using a web application
framework:

```
#[route(GET, "/")]
fn index() {
```

This `#[route]` attribute would be defined by the framework itself, as a
procedural macro. Its signature would look like this:

```
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
```

Here, we have two input `TokenStreams`: the first is for the contents of the
attribute itself, that is, the `GET, "/"` stuff. The second is the body of the
thing the attribute is attached to, in this case, `fn index() {}` and the rest
of the function's body.

Function-like macros define macros that look like function calls. For
example, an `sql!` macro:

```rust
let sql = sql!(SELECT * FROM posts WHERE id=1);
```

This macro would parse the SQL statement inside of it and check that it's
syntactically correct. This macro would be defined like this:

```
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
```

This is similar to the derive macro's signature: we get the tokens that
are inside of the parentheses and return the code we want to generate.

### `use` and macros

You can now [bring macros into scope with the `use` keyword][externmacro]. For example,
to use `serde-json`'s `json` macro, you used to write:

```rust
#[macro_use]
extern crate serde_json;

let john = json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});
```

But now, you'd write

```rust
extern crate serde_json;

use serde_json::json;

let john = json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});
```

This brings macros more in line with other items and removes the need for
`macro_use` annotations.

[externmacro]: https://github.com/rust-lang/rust/pull/50911/
[Rust 1.15]: https://blog.rust-lang.org/2017/02/02/Rust-1.15.html

## Module system improvements

The module system has long been a pain point of new Rustaceans; several of
its rules felt awkward in practice. These changes are the first steps we're
taking to make the module system feel more straightforward.

[`mod.rs` files are now optional][optionalmod]. Imagine we had a `foo`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being dropped from the release (last minute bug found)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is un-stabilized again in rust-lang/rust#55315 due to issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can mention tool attributes instead (like #[rustfmt::skip]), they are well hidden in https://github.com/rust-lang/rust/blob/master/RELEASES.md#misc in the release notes.

Copy link
Member

@jtgeibel jtgeibel Oct 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I've just opened up rust-lang/rust#55331. The tool_lints feature doesn't actually land until 1.31, even though the compiler warns and recommends the new syntax.

Edit: I've confirmed that 1.30 doesn't actually generate a warning on this when running cargo clippy. It looks like this was backed out of beta some time ago rust-lang/rust@27daef9.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtgeibel
The release notes talk about tool attributes (#[rustfmt::skip]) rather than tool lints (#[allow(clippy::something)]).
Tool attributes were indeed stabilized on 1.30.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@petrochenkov thanks a lot for the clarification, I wasn't aware those were separate. If it is added to the blog post it may be worth clarifying the distinction because I could see others being confused as well.

submodule with a `bar` submodule of its own. The directory layout would
look like this:

```text
.
├── src
│ ├── foo
│ │ └── mod.rs
│ │ └── bar.rs
│ └── lib.rs
```

In Rust 1.30, you can do this instead:

```text
.
├── src
│ ├── foo
│ │ └── bar.rs
│ ├── foo.rs
│ └── lib.rs
```

This means that you'll no longer have plenty of tabs all named `mod.rs` in
your IDE! It also eases the process of adding a submodule; before `bar`
existed, the project would look like this:

```text
.
├── src
│ ├── foo.rs
│ └── lib.rs
```

Many users found the need to move `foo.rs` into `foo/mod.rs` to be an
unncessary, strage requirement. With the new layout, you create `src/foo`,
put `bar.rs` in it, and you're done.

[optionalmod]: https://github.com/rust-lang/rust/pull/54072

There's two changes to `use` as well, in addition to the aforementioned change for
macros. The first is that you can now always [`use` an extern crate without
`::`][nocoloncolon], that is:

```rust
// old
let json = ::serde_json::from_str("...");

// new
let json = serde_json::from_str("...");
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't demonstrate use but the text indicates it should?


The trick here is that the 'old' style wasn't always needed, due to the way Rust's
module system worked:

```rust,ignore
extern crate serde_json;

fn main() {
// this works just fine; we're in the crate root, so `serde_json` is in
// scope here
let json = serde_json::from_str("...");
}

mod foo {
fn bar() {
// this doesn't work; we're inside the `foo` namespace, and `serde_json`
// isn't declared there
let json = serde_json::from_str("...");

}

// one option is to `use` it inside the module
use serde_json;

fn baz() {
// the other option is to use `::serde_json`, so we're using an absolute path
// rather than a relative one
let json = ::serde_json::from_str("...");
}
}
```

Moving a function to a submodule and having your imports break was not a great
experience. Now, `use` will check the first part of the path and see if it's an `extern
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"use will check" -> "relative paths will check"
"imports break" -> "non-imports break" (well, there's probably some better wording for "non-imports")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried a better wording, thank you :)

crate`, and if it is, use it regardless of where you're at in the module hierarchy.

[nocoloncolon]: https://github.com/rust-lang/rust/pull/54404/

Finally, [`use` also supports bringing items into scope with paths starting with
`crate`][usecrate]:

```rust
mod foo {
pub fn bar() {
// ...
}
}

// old
use ::foo::bar;
// or
use foo::bar;

// new
use crate::foo::bar;
```

The `crate` keyword at the start of the path indicates that you would like the path to
start at your crate root. Previously, paths specified after `use` would always start at
the crate root, but paths referring to items directly would start at the local path,
meaning the behavior of paths was inconsistent:

```rust
mod foo {
pub fn bar() {
// ...
}
}

mod baz {
pub fn qux() {
// old
::foo::bar();
// does not work, which is different than with `use`:
// foo::bar();

// new
crate::foo::bar();
}
}
```

Once this style becomes widely used, this will hopefully make absolute paths a bit more
clear and remove some of the ugliness of leading `::`.

All of these changes combined lead to a more straightforward understanding of how paths
resolve. Wherever you see a path like `a::b::c` someplace other than a `use` statement,
you can ask:

* Is `a` the name of a crate? Then we're looking for `b::c` inside of it.
* Is `a` the keyword `crate`? Then we're looking for `b::c` from the root of our crate.
* Otherwise, we're looking for `a::b::c` from the current spot in the module hierarchy.

The old behavior of `use` paths always starting from the crate root still applies. But
after making a one-time switch to the new style, these rules will apply uniformly to
paths everywhere, and you'll need to tweak your imports much less when moving code around.
Copy link
Contributor

@petrochenkov petrochenkov Oct 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what this paragraph is talking about, the changes stabilized in 1.30 neither reduce "import tweaking when moving code around" in any way, nor "lead to a more straightforward understanding of how paths resolve".

All of those are supposed benefits of the 2018 edition module system, that's not stabilized yet and require explicit switching to 2018 edition.
Right now (1.30 / 2015 edition) crate:: in paths is supported to simplify migration to 2018 rather than anything else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit more constructively:

  • Non-imports starting with a crate name require less tweaking when moving code around due to the "::serde_json::from_str -> serde_json::from_str" change.
  • If crate:: is used consistently in imports (the "still on 2015, but ready for 2018 migration" mode), then we have more straightforward import logic - they always start with a crate name or a special keyword.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was purely talking about moving code within submodules, not moving to or from 2015/2018, like your first bullet point


[usecrate]: https://github.com/rust-lang/rust/pull/54404/

## Raw Identifiers

[You can now use keywords as identifiers][rawidents] with some new syntax:

```rust
// define a local variable named `for`
let r#for = true;

// define a function named `for`
fn r#for() {
// ...
}

// call that function
r#for();
```

This doesn't have many use cases today, but will once you are trying to use a Rust 2015
crate with a Rust 2018 project and vice-versa because the set of keywords will be
different in the two editions; we'll explain more in the upcoming blog post about
Rust 2018.

[rawidents]: https://github.com/rust-lang/rust/pull/53236/

## Other things

Finally, you can [use the `#[panic_handler]`][panichandler] attribute to
implement panics yourself, and you can now [match on visibility keywords,
like `pub`, in macros][viskeyword] using the `vis` specifier.

[panichandler]: https://github.com/rust-lang/rust/pull/51366/
[viskeyword]: https://github.com/rust-lang/rust/pull/53370/

See the [detailed release notes][notes] for more.

### Library stabilizations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it makes sense to mention proc macro API here (https://doc.rust-lang.org/stable/proc_macro/index.html).
It was secretly stabilized in 1.29 and then never announced officially.


A few new APIs were [stabilized for this
release](https://github.com/rust-lang/rust/blob/master/RELEASES.md#stabilized-apis):

* `Ipv4Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}`
* `Ipv6Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}`
* `Iterator::find_map`

Additionally, the standard library has long had functions like `trim_left` to eliminate
whitespace on one side of some text. However, when considering RTL languages, the meaning
of "right" and "left" gets confusing. As such, we're introducing new names for these
APIs:

* `trim_left` -> `trim_start`
* `trim_right` -> `trim_end`
* `trim_left_matches` -> `trim_start_matches`
* `trim_right_matches` -> `trim_end_matches`

We plan to deprecate (but not remove, of course) the old names in Rust 1.33.

See the [detailed release notes][notes] for more.

### Cargo features

The largest feature of Cargo in this release is that we now [have a progress
bar!](https://github.com/rust-lang/cargo/pull/5995/)

> GIF goes here
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a reminder to put the gif here (or maybe asciinema?).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a GIF is nicer as it starts automatically, so it is more eye-catching.


See the [detailed release notes][notes] for more.

## Contributors to 1.30.0

Many people came together to create Rust 1.30. We couldn't have done it
without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.30.0)