Only one obvious way for Vec literals?


#1

In my opinion some parts of the Python Zen are good for more than just Python. One of its rules says “There should be one-- and preferably only one --obvious way to do it.”. Currently rustc accepts syntax like this with no warnings:

#![allow(unused_variables)]
fn main() {
    let a = vec![1, 2];
    let b = vec!(1, 2);
    let c = vec!{1, 2};
}

vec! is a macro, and that kind of Rust macros allow the use of () [] and {}. But is it a good idea to allow slightly different syntaxes for a such common collection literal as a Vec? My gut says that having only one way of writing vec literals is better.

rustfmt converts the () and {} of vec literals to [].

In other situations Rustc gives vigorous warnings (and I like that) for small syntactic problems:

#![allow(unused_variables)]
fn main() {
    let a = if (true) { 0 } else { 1 };
    while (true) {}
    let x = (1 + 1);
}

Gives:

warning: unnecessary parentheses around `if` condition
 --> ...\test.rs:3:16
  |
3 |     let a = if (true) { 0 } else { 1 };
  |                ^^^^^^ help: remove these parentheses
  |
  = note: #[warn(unused_parens)] on by default

warning: unnecessary parentheses around `while` condition
 --> ...\test.rs:4:11
  |
4 |     while (true) {}
  |           ^^^^^^ help: remove these parentheses

warning: unnecessary parentheses around assigned value
 --> ...\test.rs:5:13
  |
5 |     let x = (1 + 1);
  |             ^^^^^^^ help: remove these parentheses

warning: denote infinite loops with `loop { ... }`
 --> ...\test.rs:4:5
  |
4 |     while (true) {}
  |     ^^^^^^^^^^^^ help: use `loop`
  |
  = note: #[warn(while_true)] on by default

So is it a good idea to add a warning to rustc that suggest to always use [] for vec literals?


#2

I wonder if macros 2.0 could fix this issue in general. The obvious rule is to require braces on the definition site and on the call site to match.


#3

Yes, the plan was to “fix” this in declarative macros 2.0 somehow.


#4

I thought this was just a side-effect of how macros currently work. Basically they operate entirely with “token trees” (anything inside a set of curly braces, parens, or square brackets). By the time the token tree reaches a macro any information about what type of delimiter was used ((), [], or {}) is effectively erased.

As such you can use macros with any delimiter you want (as long as they match up, obviously) and the macro/rustc won’t care.