Idea: Shorthand syntax for scoped imports

I'm not too sure what the traditional name for such a feature would be, so searching for previous discussions has been difficult.

Summary

In OCaml, you can create an expression within the scope of another module, temporarily bringing in all items from that module for a single expression.

(* instead of *)
let x = Foo.bar + Foo.baz;;
(* you can say *)
let x = Foo.(bar + baz);;

If a similar syntax was added to Rust, certain patterns involving bitflags and repeated references to enum variants would become simpler/more concise to read/write.

Motivation

I often find myself creating a temporary scope to bring in all of the variants of an enum, such as:

enum Fruits {
    Banana,
    Apple,
    Orange
}

let my_basket = {
    use Fruits::*;
    [Banana, Banana, Apple]
};
// instead of
// let my_basket = [
//     Fruits::Banana, Fruits::Banana, Fruits::Apple
// ];

However, this pattern introduces a significant amount of visual noise into my code. The creation of a new multiline block implies to me as a reader that there are intermediate computations going on that will result in a single final value. However, there are no intermediate computations here; only an import.

What if there was shorthand for this pattern of a use followed by an immediate expression? This would result in much more concise code without the implication a multiline block brings.

let my_basket = use Fruits::* in { [Banana, Banana, Apple] }

Currently, working with bitflags from the bitflags crate is quite verbose. Below is an excerpt from the wgpu crate's "boids" example:

...
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
...

Although it seems to be an explicit decision from the developers to use the qualified path of the BufferUsages struct for all calls, dropping the crate name does little to reduce the visual redundancy.

With such a shorthand import syntax, we can reduce the excerpt from the boids example to:

... 
usage: use wgpu::BufferUsages::* in { VERTEX | STORAGE | COPY_DST },
...

Alternatives

Macro

I've tried writing a macro for such a syntax:

macro_rules! using {
    ($module:path, $what:expr) => {
        { use $module::*; $what }
    }
}

which works well with enums, but is unable to handle the constants produced within the impl for a struct. This limitations makes it a no-go for any bitflag structs made using the bitflags crate, whose constant flags are stored in the impl for the generated bitflag struct.

I don't see the difference between

And

Besides the formatting, they're essentially identical. Why not just do

let my_basket = { use Fruits::*; [Banana, Banana, Apple] };

In the first place? Sure, rustfmt may not like it, but there are other options for fixing formatting that don't require a completely new syntax.

6 Likes

Wow, that does do everything the addition aimed to do. I hadn't even considered just dropping all newlines from the block. Thank you.

This syntax looks like you are trying to access a member of foo calculated dynamically by the expression bar + baz. Which is so far from what you intend it to mean, that I expect a lot of confusion.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.