Vec! like initaliser for other collections


#1

Vec has a macro to assist in initialising a Vec with given contents, however none of the other collections in libstd have one. Many other languages have syntax for declaring e.g. a hash map in one go, including Python, Ruby, C++, and C#. Could we do something similar for at least the more commonly used collections, such as HashMap (and maybe others)? I was thinking along these lines:

let my_vec = vec![1, 2, 3]; // this is for Vec let my_hashmap = hashmap!{“one”: 1, “two”: 2, “three”: 3}; // this is for HashMap

I’m not sure if this syntax is possible, but I assume it is as vec! has square brackets instead of parentheses. What are your thoughts? Any other collections this could be useful for?


#2

I believe there have been talks about a generic seq! macro:

let my_vec: Vec<_> = seq![1,2,3];
let my_map: HashMap<_, _> = seq! { "a" => 1, "b" => 2 };

Under the covers, this would be implemented using collect:

macro_rules! seq {
  ($($k:expr => $v:expr),*) => { <make iterator of (k, v) tuples>.collect() };
  ($($(v:expr),*) => { <make iterator of vs>.collect() };
}

#3

I somewhat dislike the x => y syntax. It has no precedence within Rust, and it reminds me of Perl (or Ruby, if I’m feeling generous). We should take care not to re-use any operator that could be used inside keys or values. Thus, I can see the following alternatives:

  • x=y (Lua) has the benefit of looking like an assignment within the namespace of the map, at the cost of looking like an assignment. Since we would not want to mix assignments and our macro, it would be ok to re-use the = operator.
  • x:y (JSON, python, just about everywhere) has the benefit of not looking like an assignment and being familiar to the huge group of python/Javascipt/…etc. developers at the cost of looking like a Rust type declaration.
  • x->y looks like a bastardization of a function and a binding and like => takes two sigils, but (IMHO) looks a bit cleaner and cannot be confused with either an assignment or a type declaration.

#4

I actually quite like “=>” for the syntax. It is already used in matching, and this has similar semantics - match “one” with 1.

I dislike the others, especially the second as you wouldn’t be able to include type decelerations in the list, and the third as you couldn’t use lambdas with explicit return types. The first one looks too much like assignment for me.


#5

Agreed, the => syntax is used for pattern matching. Ok, so there is some precedence in Rust, I’m gonna retract my statement; I guess I can live with it. :smile:


#6

There’s an RFC for seq![].


#7

Hmmm. I suppose it would be entirely backwards compatible, except that vec! would probably be removed. That would mean it needs to be done before or after 1.x.


#8

I doubt vec! will ever be removed.


#9

It would break a huge amount of code, but assuming seq! is the same syntax

  • I think it is (?) based on above comments - then a simple find and replace would fix it

#10

Perhaps go the Java route and deprecate vec! in 1.1 and remove it in 7.5 or something? :smile:


#11

vec! is strictly better than seq! though; seq requires type hints for the type of collection, while vec doesn’t. (vec might still need type hints for the contents, but this is quite rare in my experience, particularly with integer fallback)


#12

On the same note, would it make sense to split the macro to map! and tree! or something similar?


#13

I a actually have map!() macro somewhere in depth of my code. But I like universal approach of seq!(): I have terrible memory, and the less things to remember, three better.