-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add hashmap, hashset, treemap, and treeset macros #14726
Comments
I am strongly in favor of getting these macros added somewhere simply because of how common the collections are used. We need a shortcut. |
If this gets added, I'm strongly in favor of using
|
I'm not so sure about this. Colons are already used for type annotations and namespaces. I think |
@TyOverby Didn't the collections get moved to std? I'm fine with either syntax. |
Oh wow, they totally did. I wonder if Vec will get moved there too? |
In any case, I think this is a change that requires an RFC. I would prefer having a generic macro (or two of them) that allows constructing any container type, rather than having to manually create one for each type and forcing other data structure implementers to do the same. |
I meant in |
@huonw How would that generic macro figure out the type of container to create? Would you have to pass in the type? I can create an RFC if no one else wants to (note: I don't want to, I wouldn't be able to comment on implementation at all). |
Using traits, something like trait Seq<T>: Default {
fn add_elem(&mut self, x: T);
}
macro_rules! seq {
($($e: expr),*) => {{
let mut _thing = Default::default();
$( _thing.add_elem($e); )*
_thing
}}
}
let s: HashSet<int> = seq!(1, 2, 3); // HashSet impls Seq<int>
let s: HashMap<int, int> = seq!((1, 10), (2, 20), (3, 30); // impls Seq<(int, int)> (I don't have time to write an RFC atm, maybe in a week and a half.) |
Ah, I see. I'll post in this thread next week then to ask about the RFC unless anyone else gets around to writing it. |
Isn't |
@gereeter yes, but it would be quite ineffficient. |
@huonw Would that macro work? I tried to write a similar one for the #![feature(macro_rules)]
extern crate collections;
macro_rules! map {
($($k: expr => $v: expr),*) => {{
use std::default::Default;
let mut _thing = Default::default();
$( _thing.insert($k, $v); )* //~ ERROR the type of this value must be known in this context
_thing
}}
}
pub fn main() {
use collections::treemap::TreeMap;
let x: TreeMap<int, int> = map!(1 => 2);
} |
Ah, looks like Rust's current type inference might not be powerful enough (I have no idea if we extend it to make it work). Something like (With this, even |
I'd still like to see an RFC for this if anyone has the time. |
I was thinking about something like this. I agree that something generic would be preferred. We would need to figure out which syntax we would like. This is a working implementation @huonw mentioned: playpen Which would give a syntax like:
Another alternative would be to have a syntax like:
However I could not get the macro to recognize
Overall I think it would be nicer to have the original syntax idea:
But I have no clue what we would have to introduce to make that work. |
It seems like RFC #143 may allow something similar. |
That macro can be implemented using what we have today without using any new trait: #![feature(macro_rules)]
use std::collections::{HashMap,HashSet};
macro_rules! seq {
($($x:expr),+) => {
[$($x,)+].iter().map(|&x| x).collect()
}
}
fn main() {
let set: HashSet<int> = seq!(1, 2, 3);
let map: HashMap<int, int> = seq!((1, 10), (2, 20), (3, 30));
println!("Set: {}", set);
println!("Map: {}", map);
} That macro only works for I don't claim that's the most efficient implementation, just want to show that it can be readily implemented today. |
@japaric that's nice, thanks! For it to be accepted into |
It should also make use of |
Be sure to implement a rules which allow for trailing commas. For example: macro_rules! vec(
($($e:expr),*) => ({
// leading _ to allow empty construction without a warning.
let mut _temp = ::std::vec::Vec::new();
$(_temp.push($e);)*
_temp
});
($($e:expr),+,) => (vec!($($e),+))
) |
I've crafted a
I'm leaving a (minimal) copy of the code here for posteriority: #![feature(macro_rules)]
trait Seq<T> {
fn with_capacity(capacity: uint) -> Self;
// HACK: A method doesn't play well with the inference engine, use a static function instead
fn add_elem(seq: &mut Self, elem: T);
}
// FIXME (rust-lang/rfcs#88) Use the `$#($arg)` syntax instead of the `count_args!` macro
macro_rules! count_args {
() => { 0 };
($x:expr) => { 1 };
($head:expr, $($tail:expr),+) => { 1 + count_args!($($tail),+) };
}
macro_rules! seq {
// List style: Vec, {Hash,Tree}Set, etc
($($x:expr),*) => ({
let mut _temp = Seq::with_capacity(count_args!($($x),*));
$(Seq::add_elem(&mut _temp, $x);)*
_temp
});
// Map style: {Hash,Tree}Map, etc
($($k:expr => $v:expr),*) => ({
let mut _temp = Seq::with_capacity(count_args!($(($k, $v)),*));
$(Seq::add_elem(&mut _temp, ($k, $v));)*
_temp
});
// Trailing comma <3
($($x:expr),+,) => { seq!($($x),+) };
($($k:expr => $v:expr),+,) => { seq!($($k => $v),+) };
} What do you guys think of this implementation? |
Nice @japaric, I like it. You could write an RFC for this if you want? |
@nick29581 Could you please move this issue to the RFC repo? |
This issue has been moved to the RFCs repo: rust-lang/rfcs#542 |
@japaric It'd be nice if you could put the seq implementation in a crate so I could use it throughout my projects without copying and pasting. |
@gsingh93 There's a link to my out of tree implementation (i.e. a cargo crate) in the top comment of the RFC. However, I'm not maintaining the crate anymore - I've listed some alternatives in the README though. You can either use one of the listed alternatives or maintain a fork of my original crate. |
minor: Lock paths-filter action to a specific commit
I wanted to create an issue first asking about this before submitting a pull request.
Can I go ahead an implement
hashmap!()
,hashset!()
,treemap!()
, andtreeset!()
macros for constructing those collections with the given arguments? The syntax would be:I already have these macros implemented in my own projects, so I'd just have to add them to macros.rs.
If I can add these, is there a process for testing macros? Or would I just replace all occurrences of hash{map,set} and tree{map,set} creation in the tests by the macros?
The text was updated successfully, but these errors were encountered: