diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 63008503..eb5cc92b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -85,3 +85,13 @@ - [MSVC toolchain support](rust-2018/platform-and-target-support/msvc-toolchain-support.md) - [MUSL support for fully static binaries](rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md) - [`cdylib` crates for C interoperability](rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md) + +## The Next Edition + +- [The Next Edition](rust-next/index.md) + - [Next-Specific Changes](rust-next/edition-changes.md) + - [The dbg! macro](rust-next/dbg-macro.md) + - [No jemalloc by default](rust-next/no-jemalloc.md) + - [Uniform Paths](rust-next/uniform-paths.md) + - [`literal` macro matcher](rust-next/literal-macro-matcher.md) + - [`?` operator in macros](rust-next/qustion-mark-operator-in-macros.md) \ No newline at end of file diff --git a/src/rust-next/dbg-macro.md b/src/rust-next/dbg-macro.md new file mode 100644 index 00000000..a2ac7ad8 --- /dev/null +++ b/src/rust-next/dbg-macro.md @@ -0,0 +1,104 @@ +# The dbg! macro + +![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg) + +The `dbg!` macro provides a nicer experience for debugging than `println!`: + +```rust +fn main() { + let x = 5; + + dbg!(x); +} +``` + +If you run this program, you'll see: + +```text +[src/main.rs:4] x = 5 +``` + +You get the file and line number of where this was invoked, as well as the +name and value. Additionally, `println!` prints to the standard output, so you +really should be using `eprintln!` to print to standard error. `dbg!` does the +right thing and goes to stderr. + +It even works in more complex circumstances. Consider this factorial example: + +```rust +fn factorial(n: u32) -> u32 { + if n <= 1 { + n + } else { + n * factorial(n - 1) + } +} +``` + +If we wanted to debug this, we might write it like this with `eprintln!`: + +```rust +fn factorial(n: u32) -> u32 { + eprintln!("n: {}", n); + + if n <= 1 { + eprintln!("n <= 1"); + + n + } else { + let n = n * factorial(n - 1); + + eprintln!("n: {}", n); + + n + } +} +``` + +We want to log `n` on each iteration, as well as have some kind of context +for each of the branches. We see this output for `factorial(4)`: + +```text +n: 4 +n: 3 +n: 2 +n: 1 +n <= 1 +n: 2 +n: 6 +n: 24 +``` + +This is servicable, but not particularly great. Maybe we could work on how we +print out the context to make it more clear, but now we're not debugging our +code, we're figuring out how to make our debugging code better. + +Consider this version using `dbg!`: + +```rust +fn factorial(n: u32) -> u32 { + if dbg!(n <= 1) { + dbg!(1) + } else { + dbg!(n * factorial(n - 1)) + } +} +``` + +We simply wrap each of the various expressions we want to print with the macro. We get this output instead: + +```text +[src/main.rs:3] n <= 1 = false +[src/main.rs:3] n <= 1 = false +[src/main.rs:3] n <= 1 = false +[src/main.rs:3] n <= 1 = true +[src/main.rs:4] 1 = 1 +[src/main.rs:5] n * factorial(n - 1) = 2 +[src/main.rs:5] n * factorial(n - 1) = 6 +[src/main.rs:5] n * factorial(n - 1) = 24 +[src/main.rs:11] factorial(4) = 24 +``` + +Because the `dbg!` macro returns the value of what it's debugging, instead of +`eprintln!` which returns `()`, we need to make no changes to the structure of +our code. Additionally, we have vastly more useful output. diff --git a/src/rust-next/edition-changes.md b/src/rust-next/edition-changes.md new file mode 100644 index 00000000..58475292 --- /dev/null +++ b/src/rust-next/edition-changes.md @@ -0,0 +1,3 @@ +# Next-Specific Changes + +There have been no specific changes accepted for the next edition yet. \ No newline at end of file diff --git a/src/rust-next/index.md b/src/rust-next/index.md new file mode 100644 index 00000000..195118dd --- /dev/null +++ b/src/rust-next/index.md @@ -0,0 +1,7 @@ +# The Next Edition + +We have not decided if and when the next edition will ship; there is talk of +a 2021 edition to keep up the three-year schedule, but that has not been +formally decided. + +Until we do, this section keeps track of changes that landed after Rust 2018. \ No newline at end of file diff --git a/src/rust-next/literal-macro-matcher.md b/src/rust-next/literal-macro-matcher.md new file mode 100644 index 00000000..1b84aade --- /dev/null +++ b/src/rust-next/literal-macro-matcher.md @@ -0,0 +1,18 @@ +# literal macro matcher + +![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg) + +A new `literal` matcher was added for macros: + +```rust +macro_rules! m { + ($lt:literal) => {}; +} + +fn main() { + m!("some string literal"); +} +``` + +`literal` matches against literals of any type; string literals, numeric +literals, `char` literals. diff --git a/src/rust-next/no-jemalloc.md b/src/rust-next/no-jemalloc.md new file mode 100644 index 00000000..cd024108 --- /dev/null +++ b/src/rust-next/no-jemalloc.md @@ -0,0 +1,43 @@ +# No jemalloc by default + +![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg) + +Long, long ago, Rust had a large, Erlang-like runtime. We chose to use +jemalloc instead of the system allocator, because it often improved +performance over the default system one. Over time, we shed more and more of +this runtime, and eventually almost all of it was removed, but jemalloc was +not. We didn't have a way to choose a custom allocator, and so we couldn't +really remove it without causing a regression for people who do need +jemalloc. + +Also, saying that jemalloc was always the default is a bit UNIX-centric, as +it was only the default on some platforms. Notably, the MSVC target on +Windows has shipped the system allocator for a long time. + +While jemalloc usually has great performance, that's not always the case. +Additionally, it adds about 300kb to every Rust binary. We've also had a host +of other issues with jemalloc in the past. It has also felt a little strange +that a systems language does not default to the system's allocator. + +For all of these reasons, once Rust 1.28 shipped a way to choose a global +allocator, we started making plans to switch the default to the system +allocator, and allow you to use jemalloc via a crate. In Rust 1.32, we've +finally finished this work, and by default, you will get the system allocator +for your programs. + +If you'd like to continue to use jemalloc, use the jemallocator crate. In +your Cargo.toml: + +```toml +jemallocator = "0.1.8" +``` + +And in your crate root: + +```rust,ignore +#[global_allocator] +static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +``` + +That's it! If you don't need jemalloc, it's not forced upon you, and if you +do need it, it's a few lines of code away. diff --git a/src/rust-next/qustion-mark-operator-in-macros.md b/src/rust-next/qustion-mark-operator-in-macros.md new file mode 100644 index 00000000..bed0381d --- /dev/null +++ b/src/rust-next/qustion-mark-operator-in-macros.md @@ -0,0 +1,14 @@ +# ? operator in macros + +![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg) + +`macro_rules` macros can use `?`, like this: + +```rust +macro_rules! bar { + ($(a)?) => {} +} +``` + +The `?` will match zero or one repetitions of the pattern, similar to the +already-existing `*` for "zero or more" and `+` for "one or more." diff --git a/src/rust-next/uniform-paths.md b/src/rust-next/uniform-paths.md new file mode 100644 index 00000000..27a91abf --- /dev/null +++ b/src/rust-next/uniform-paths.md @@ -0,0 +1,23 @@ +# Uniform Paths + +![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg) + +Rust 2018 added several improvements to the module system. We have one last +tweak landing in 1.32.0. Nicknamed "uniform paths", it permits previously +invalid import path statements to be resolved exactly the same way as +non-import paths. For example: + +```rust,edition2018 +enum Color { + Red, + Green, + Blue, +} + +use Color::*; +``` + +This code did not previously compile, as use statements had to start with +`super`, `self`, or `crate`. Now that the compiler supports uniform paths, +this code will work, and do what you probably expect: import the variants of +the Color enum defined above the `use` statement.