Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: Macro syntax to count sequence repetitions #88
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
sinistersnare
commented
May 23, 2014
|
Off Topic: You can see the rendered view by going to the files changed tab and clicking |
This comment has been minimized.
This comment has been minimized.
|
@sinistersnare You can go to the Files changed tab and click |
This comment has been minimized.
This comment has been minimized.
|
Under "Alternatives" you say that a #![feature(macro_rules)]
macro_rules! vec_new(
($($e:expr),*) => ({
// leading _ to allow empty construction without a warning.
let mut _temp = ::std::vec::Vec::with_capacity(arity!($($e),*));
$(_temp.push($e);)*
_temp
});
($($e:expr),+,) => (vec_new!($($e),+))
)
// Trust me, you *really* want the helper macros...
// If you attempt this without them, may God have mercy on your soul.
macro_rules! arity(
($($thing:expr),+) => (arity_expr!($($thing),*));
($($thing:pat),+) => (arity_pat!($($thing),*));
() => (0);
)
macro_rules! arity_expr(
($head:expr, $($tail:expr),*) => (1 + arity_expr!($($tail),*));
($last:expr) => (1);
)
macro_rules! arity_pat(
($head:pat, $($tail:pat),*) => (1 + arity_pat!($($tail),*));
($last:pat) => (1);
)
fn test_arity() {
assert!(arity!() == 0);
// expr
assert!(arity!(9) == 1);
assert!(arity!(9,9,9) == 3);
// ident - matched by expr
assert!(arity!(Nine) == 1);
assert!(arity!(Nine,Nine,Nine) == 3);
// ty - matched by expr
assert!(arity!(Option::<int>) == 1);
assert!(arity!(Option::<int>,Option::<int>,Option::<int>) == 3);
// block - matched by expr
assert!(arity!({9;9}) == 1);
assert!(arity!({9;9},{9;9},{9;9}) == 3);
// pat
assert!(arity!(foo @ _) == 1);
assert!(arity!(foo @ _,foo @ _,foo @ _) == 3);
println!("All tests pass");
}
fn main() {
test_arity();
let v = vec_new![7,8,9];
println!("{}", v);
}I can't think of any cases where this wouldn't suffice. True, |
This comment has been minimized.
This comment has been minimized.
Eh, I don't know about that: #![feature(macro_rules)]
macro_rules! iota(
($($thing:expr),+) => (iota_expr!(1, $($thing),*));
($($thing:pat),+) => (iota_pat!(1, $($thing),*));
() => (());
)
macro_rules! iota_expr(
($id:expr, $head:expr, $($tail:expr),*) => ({
println!("expr {}", $id); iota_expr!($id+1, $($tail),*);
});
($id:expr, $last:expr) => ({ println!("expr {}", $id); });
)
macro_rules! iota_pat(
($id:expr, $head:pat, $($tail:pat),*) => ({
println!("pat {}", $id); iota_pat!($id+1, $($tail),*);
});
($id:expr, $last:pat) => ({ println!("pat {}", $id); });
)
fn test_iota() {
println!("empty test");
iota!();
// expr
println!("expr test");
iota!(9);
iota!(9,9,9);
// ident - matched by expr
println!("ident test");
iota!(Nine);
iota!(Nine,Nine,Nine);
// ty - matched by expr
println!("ty test");
iota!(Option::<int>);
iota!(Option::<int>,Option::<int>,Option::<int>);
// block - matched by expr
println!("block test");
iota!({9;9});
iota!({9;9},{9;9},{9;9});
// pat
println!("pat test");
iota!(foo @ _);
iota!(foo @ _,foo @ _,foo @ _);
}
fn main() {
test_iota();
}Though this pattern does get mightily inconvenient, mighty fast. The idea of iinitializing statics that utilize the current iteration number is a tantalizing problem, but I'm not sure if it's possible using this approach. |
This comment has been minimized.
This comment has been minimized.
|
@bstrie It didn't occur to me that you could have the same macro match multiple different types of nonterminals, although I would not be surprised if you can trigger parse errors that way (e.g. the first arg could match as an expression, so it does, but then the second arg is a real pattern and can't match as an expr). As for |
This comment has been minimized.
This comment has been minimized.
|
Yeah, your |
This comment has been minimized.
This comment has been minimized.
|
Would something like |
This comment has been minimized.
This comment has been minimized.
|
@huonw That seems extremely hacky to be exporting from libstd. |
This comment has been minimized.
This comment has been minimized.
|
It seems far more controlled (and less hacky) than an count macro that just takes arbitrary arguments without a "type" (e.g. However, I think I still prefer a proper repeat-count for |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
May 26, 2014
|
I think we could implement If we were willing to squirrel information away into the |
This comment has been minimized.
This comment has been minimized.
|
@paulstansifer Do you feel that a procedural macro would be the better approach? I feel like that's trying to paper over a deficiency in the macro syntax. Better to just fix macros to be able to count the sequences directly, then to try and recreate that ability externally. |
This comment has been minimized.
This comment has been minimized.
|
Servo could use this. For now, we have a Python template that generates Rust code equivalent to a struct with a bunch of The plan is to replace the template with procedural macros, but this RFC would allow that particular bit to be a much simpler |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
May 27, 2014
|
@kballard At least for |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
May 27, 2014
|
@SimonSapin Unfortunately, I doubt that you'll be able to write I have an idea for a change we could make to at least allow |
This comment has been minimized.
This comment has been minimized.
|
I don’t know how the parser works exactly, but this compiles fine: static A: uint = 42;
static B: [u8, ..A] = [0, ..A]; |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
May 27, 2014
|
@SimonSapin Oh, sure enough! It's syntactically an expression (handled by |
This comment has been minimized.
This comment has been minimized.
|
Using a hack to try and count the number of repetitions seems distinctly sub-par to just letting the macro parser count them itself, since the macro parser should already know the answer. It also seems more fragile (e.g. that multi-typed |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
May 27, 2014
|
@kballard The solution that I proposed shouldn't be fragile at all. I admit that it's a little funny to essentially say "Paste this in, separated by commas, and then count the commas", but I don't think it's too bad. And name pollution is exactly my concern; instead of claiming a punctuation sequence for the concept, we can just use a descriptive name, freeing That said, I am sympathetic to the idea of just acquiring the information directly, since it'd be shorter to write. But I really like the idea of implementing a feature without having to change the language. |
This comment has been minimized.
This comment has been minimized.
|
@kballard Is there an example of a case where E.g. the discussion above has led me to think that If so, I recommend you revise the RFC so that this feature is provided via a macro like |
This comment has been minimized.
This comment has been minimized.
|
@pnkfelix match count {
Some(arity!($($arg),*)) => {
println!("the count matches the args");
}
_ => {
println!("wrong arg count");
}
}However |
This comment has been minimized.
This comment has been minimized.
|
Those limitations are just for the |
This comment has been minimized.
This comment has been minimized.
|
@rkjnsn You're right, I was only thinking of the Still, I think that the idea of using It also just plain seems weird. For it to work on all nonterminal types, it needs to work on the raw token stream, and literally just count the number of commas and add 1. That's the only way it would work with e.g. the Basically, the |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
To clarify: I don’t care about what it looks like (custom syntax or built-in macro) as long as both the total count and the current iteration number can be obtained somehow. |
This comment has been minimized.
This comment has been minimized.
|
I can appreciate the argument that its bad to reserve the global name cc @jbclements who might be able to weigh in with some perspective on where the macro system is going. I will have to review the procedural macro system a bit more before I can comment further on @kballard's other point. (And I will also have to play around a little with the current iteration number desiderata. That does indeed seem important.) @kballard : In the meantime, it would be good to add an motivating example for |
This comment has been minimized.
This comment has been minimized.
jbclements
commented
Jun 25, 2014
|
In my mind, it looks like adding |
This comment has been minimized.
This comment has been minimized.
paulstansifer
commented
Jun 25, 2014
|
@kballard It'll never make sense to reify the INTERPOLATED tokens: the performance cost would be high, and it would buy nothing. I agree that "comma-separate, then count commas" is kinda weird, but I argue that reserving a name is strictly better than reserving a punctuation character. After all, there are tons of possible names, but not a lot of punctuation. What's more, |
This comment has been minimized.
This comment has been minimized.
That's certainly plausible, but I don't like making a macro that relies upon the current implementation details of nonterminal tokens.
The
I disagree. It's actually a bad name. It's not actually finding the arity of anything at all, it's just a hack that tries to count nonterminals by counting commas. Offhand, I'd expect something like |
alexcrichton
force-pushed the
rust-lang:master
branch
from
6357402
to
e0acdf4
Sep 11, 2014
aturon
force-pushed the
rust-lang:master
branch
from
4c0bebf
to
b1d1bfd
Sep 16, 2014
This comment has been minimized.
This comment has been minimized.
|
@kballard do you think there are more points that need to be discussed here? Assuming not, would you like to attempt to update the RFC in the manner I outlined earlier? Or should we perhaps plan to postpone this work for post 1.0, since |
This comment has been minimized.
This comment has been minimized.
|
@pnkfelix I don't think there's anything more to discuss. I've actually had this page open on my main computer for a few weeks, to remind me to get around to updating the RFC, I just haven't had the time lately. I don't think I'll have time tonight either, but I'll try to get to it sometime this week. My biggest concern with postponing this to after 1.0 is that |
This comment has been minimized.
This comment has been minimized.
|
I think we're free to mess with |
This comment has been minimized.
This comment has been minimized.
|
Looks like rust-lang/rust@02d976a fixed the performance of |
This comment has been minimized.
This comment has been minimized.
|
NB: There is currently no way to get the repetition number (without writing a compiler plugin.) |
This comment has been minimized.
This comment has been minimized.
|
@kballard given SimonSapin's observation from yesterday, I am inclined to postpone this RFC to be addressed post 1.0. Do you think that's reasonable? |
This comment has been minimized.
This comment has been minimized.
|
@pnkfelix There's still plenty of use for this RFC. For example, there's a macro in the compiler (at least one, but possibly more than one) that could really benefit from this RFC (IIRC it wants the repetition number feature). And I seem to recall a couple of months ago having code in a personal project that could have used the repetition number feature as well. That said, if it's not clear that we want to take this yet, postponing to after 1.0 is acceptable. The |
This comment has been minimized.
This comment has been minimized.
|
(unassigning self; I think we should close as postponed.) |
pnkfelix
removed their assignment
Oct 23, 2014
pnkfelix
referenced this pull request
Oct 23, 2014
Open
macro_rules should expose accessors for total iteration count and current iteration number #407
This comment has been minimized.
This comment has been minimized.
|
@kballard The team agress that there is definitely utility in this feature. But we don't think there is a pressing need to put this extension in before 1.0. So we are closing as postponed. |
pnkfelix
closed this
Oct 23, 2014
This comment has been minimized.
This comment has been minimized.
|
(p.s. @kballard thanks for all the effort you put into this. I really do think we will get something good out of this process once we can come back around to addressing this feature.) |
Centril
referenced this pull request
Feb 5, 2015
Closed
added bitflags_values! helper, now possible to add values later. #3
This comment has been minimized.
This comment has been minimized.
@kballard for completeness, that's easily fixed. The following seems to work for everything but item and meta (it allows mixed lists but there shouldn't be any ambiguity): macro_rules! arity {
($e:tt, $($toks:tt)+) => { 1 + arity!($($toks)+) };
($e:tt) => { 1 };
($e:pat, $($toks:tt)+) => { 1 + arity!($($toks)+) };
($e:pat) => { 1 };
($e:expr, $($toks:tt)+) => { 1 + arity!($($toks)+) };
($e:expr) => { 1 };
() => { 0 };
} |
This comment has been minimized.
This comment has been minimized.
alkis
commented
Oct 14, 2015
|
@kballard are you still pursuing this? I am in need of the repetition index in some macros I am writing and there is currently no way of getting this in the current state of macros. Is the discussion done here folded into some other rfc that would provide such functionality in some other way? Or do you have plans of pursuing this rfc further? |
This comment has been minimized.
This comment has been minimized.
|
@alkis it's possible but you need to use recursion (you can't do it with the |
This comment has been minimized.
This comment has been minimized.
alkis
commented
Oct 14, 2015
|
@Stebalien if you use recursion the repetition index will not be a literal but an expression. The index of the N'th item will expand to something like 0 + 1 + 1 + ... + 1. If you want the index to be used for accessing an element of a tuple unfortunately an expression won't work. AFAIK only a literal works. |
This comment has been minimized.
This comment has been minimized.
|
@alkis I see. No, this doesn't work with tuples etc. |
This comment has been minimized.
This comment has been minimized.
alkis
commented
Oct 20, 2015
|
So what needs to be done to advance this RFC? |
This comment has been minimized.
This comment has been minimized.
bwo
commented
Jun 27, 2017
|
is this rfc abandoned? superseded? |
This comment has been minimized.
This comment has been minimized.
|
I think procedural macros rust-lang/rust#38356 will make this largely unnecessary. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin Procedural macros are generally a heavy-weight solution and counting is something I've needed quite often in declarative macros (although building a |
This comment has been minimized.
This comment has been minimized.
|
At least building this as a procedural macro outside of the standard library would make it easier to make a case for inclusion in |
This comment has been minimized.
This comment has been minimized.
|
Oh, I see. Good point! |
lilyball commentedMay 23, 2014
Rendered view