The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,977 other subscribers

Rust is jet another language allowing assigning to _ for discarding assignment results (like function calls)

Posted by jpluimers on 2022/09/16

Rust is a programming language that very much emphasises safety.

One of the cornerstones is that it warns on constructs that might lose information or make object lifetime unclear.

An example is discarding function results: historically you will get a warning like warning: unused `std::result::Result` that must be used that you can resolve by applying a let statement assigning to the _ underscore pattern which will be discarded at the end of the statement like this:

let _ = foo();

By sheer coincidence, I bumped into [Wayback/Archive] David Tolnay on Twitter: “You know how when you ignore an error from a function because it’s okay it failed, and otherwise you get “warning: unused Result that must be used”, the past 7 years we’ve all been doing it like this?— let _ = foo(); Turns out since Rust 1.59 it can be just: _ = foo();.

I could not directly find this in the release notes, which is caused by the fact that – like in most programming languages – the naming of constructs usually is far less comprehensible than their actual practical usage. You see this both in the references below and (regrettably but unavoidably) in mu current blog post.

The practical solution now is much shorter:

_ = foo();

This turns the let statement assigning to an underscore pattern into an underscore expression.

The compiler change that made this possible is centered around another programming language concept: destructuring assignment which allows to map assignments from one data structure to another data structure (in its simplest form from an array or structure to individual variables).

The below steps made me find the actual issue and commit adding the improvement, each step tracking deeper into the what, why and how:

  1. [Wayback/Archive] rust/ version 1.590 (2022-02-24) at master · rust-lang/rust
  2. [Wayback/Archive] Stabilize `destructuring_assignment` by jhpratt · Pull Request #90521 · rust-lang/rust
  3. [Wayback/Archive] Tracking Issue for `destructuring_assignment` · Issue #71126 · rust-lang/rust
  4. [Wayback/Archive] Make `_` an expression, to discard values in destructuring assignments by fanzier · Pull Request #79016 · rust-lang/rust
    With this PR, an underscore _ is parsed as an expression but is allowed only on the left-hand side of a destructuring assignment. There it simply discards a value, similarly to the wildcard _ in patterns. For instance,
    (a, _) = (1, 2)
    will simply assign 1 to a and discard the 2. Note that for consistency,
    _ = foo
    is also allowed and equivalent to just foo.
  5. [Wayback/Archive] Destructuring assignment by varkor · Pull Request #2909 · rust-lang/rfcs
    We allow destructuring on assignment, as in let declarations. For instance, the following are now
    (a, (b.x.y, c)) = (0, (1, 2));
    (x, y, .., z) = (1.0, 2.0, 3.0, 4.0, 5.0);
    [_, f, *baz()] = foo();
    [g, _, h, ..] = ['a', 'w', 'e', 's', 'o', 'm', 'e', '!'];
    Struct { x: a, y: b } = bar();
    Struct { x, y } = Struct { x: 5, y: 6 };
    This brings assignment in line with let declaration, in which destructuring is permitted. This will simplify and improve idiomatic code involving mutability.
  6. [Wayback/Archive] Implement destructuring assignment by fanzier · Pull Request #71156 · rust-lang/rust

The cool thing about drilling deeper is that it taught me how the processes around maintaining the Rust repository are organised (especially the tracking issue).

Rust destructuring examples

Since rust goes further than simple destructuring, I added a few references to the documentation from [Wayback/Archive] Destructuring – Rust By Example:

The ecosystem

This new language constructs now leads for the need of surrounding tooling like lint tools or parsers to be updates just as mentioned in these issues:

Similarly the community Rust wiki needs to be updated as it only reflects the former let statement: [Wayback/Archive] Underscore – Rust Community Wiki

Underscores in let bindings[edit]

Since let accepts a patternlet _ = can be used to ignore a #[must_use] value such as a ResultThis links to official Rust documentation in order to suppress compiler warnings.

let _ = std::fs::remove_file("file.txt"); // Ignore the result

Note that it’s often better to unwrap the result instead, to make sure that errors aren’t silently discarded.

This is cool, as it means the ecosystem will quickly adopt the new language feature.




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: