Uh oh!
There was an error while loading. Please reload this page.
RFC: Macro syntax to count sequence repetitions - #88
Conversation
huonw
commented
May 23, 2014
sinistersnare
commented
May 23, 2014
Off Topic: You can see the rendered view by going to the files changed tab and clicking |
lilyball
commented
May 23, 2014
@sinistersnare You can go to the Files changed tab and click |
bstrie
commented
May 23, 2014
Under "Alternatives" you say that a #![feature(macro_rules)]macro_rules! vec_new(($($e:expr),*) => ({// leading _ to allow empty construction without a warning.letmut _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);)fntest_arity(){assert!(arity!() == 0);// exprassert!(arity!(9) == 1);assert!(arity!(9,9,9) == 3);// ident - matched by exprassert!(arity!(Nine) == 1);assert!(arity!(Nine,Nine,Nine) == 3);// ty - matched by exprassert!(arity!(Option::<int>) == 1);assert!(arity!(Option::<int>,Option::<int>,Option::<int>) == 3);// block - matched by exprassert!(arity!({9;9}) == 1);assert!(arity!({9;9},{9;9},{9;9}) == 3);// patassert!(arity!(foo @ _) == 1);assert!(arity!(foo @ _,foo @ _,foo @ _) == 3);println!("All tests pass");}fnmain(){test_arity();let v = vec_new![7,8,9];println!("{}", v);}I can't think of any cases where this wouldn't suffice. True, |
bstrie
commented
May 23, 2014
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);});)fntest_iota(){println!("empty test");iota!();// exprprintln!("expr test");iota!(9);iota!(9,9,9);// ident - matched by exprprintln!("ident test");iota!(Nine);iota!(Nine,Nine,Nine);// ty - matched by exprprintln!("ty test");iota!(Option::<int>);iota!(Option::<int>,Option::<int>,Option::<int>);// block - matched by exprprintln!("block test");iota!({9;9});iota!({9;9},{9;9},{9;9});// patprintln!("pat test");iota!(foo @ _);iota!(foo @ _,foo @ _,foo @ _);}fnmain(){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. |
lilyball
commented
May 23, 2014
@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 |
lilyball
commented
May 23, 2014
Yeah, your |
huonw
commented
May 23, 2014
Would something like |
lilyball
commented
May 23, 2014
@huonw That seems extremely hacky to be exporting from libstd. |
huonw
commented
May 23, 2014
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 |
paulstansifer
commented
May 26, 2014
I think we could implement If we were willing to squirrel information away into the |
lilyball
commented
May 26, 2014
@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. |
SimonSapin
commented
May 26, 2014
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 |
paulstansifer
commented
May 27, 2014
@kballard At least for |
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 |
SimonSapin
commented
May 27, 2014
I don’t know how the parser works exactly, but this compiles fine: staticA:uint = 42;staticB:[u8, ..A] = [0, ..A]; |
paulstansifer
commented
May 27, 2014
@SimonSapin Oh, sure enough! It's syntactically an expression (handled by |
lilyball
commented
May 27, 2014
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 |
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. |
pnkfelix
commented
Jun 25, 2014
@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 |
lilyball
commented
Jun 25, 2014
@pnkfelix match count {Some(arity!($($arg),*)) => {println!("the count matches the args");}
_ => {println!("wrong arg count");}}However |
rkjnsn
commented
Jun 25, 2014
Those limitations are just for the |
lilyball
commented
Jun 25, 2014
@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 |
SimonSapin
commented
Jun 25, 2014
|
SimonSapin
commented
Jun 25, 2014
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. |
pnkfelix
commented
Jun 25, 2014
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 |
jbclements
commented
Jun 25, 2014
In my mind, it looks like adding |
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, |
lilyball
commented
Jun 25, 2014
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 |
pnkfelix
commented
Sep 30, 2014
@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 |
lilyball
commented
Sep 30, 2014
@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 |
sfackler
commented
Sep 30, 2014
I think we're free to mess with |
SimonSapin
commented
Oct 13, 2014
Looks like rust-lang/rust@02d976a fixed the performance of |
mahkoh
commented
Oct 13, 2014
NB: There is currently no way to get the repetition number (without writing a compiler plugin.) |
pnkfelix
commented
Oct 14, 2014
@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? |
lilyball
commented
Oct 14, 2014
@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 |
pnkfelix
commented
Oct 23, 2014
(unassigning self; I think we should close as postponed.) |
pnkfelix
commented
Oct 23, 2014
@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
commented
Oct 23, 2014
(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.) |
Stebalien
commented
Jun 7, 2015
@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};} |
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? |
Stebalien
commented
Oct 14, 2015
@alkis it's possible but you need to use recursion (you can't do it with the |
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. |
Stebalien
commented
Oct 14, 2015
@alkis I see. No, this doesn't work with tuples etc. |
alkis
commented
Oct 20, 2015
So what needs to be done to advance this RFC? |
bwo
commented
Jun 27, 2017
is this rfc abandoned? superseded? |
SimonSapin
commented
Jun 29, 2017
I think procedural macros rust-lang/rust#38356 will make this largely unnecessary. |
Stebalien
commented
Jun 29, 2017
@SimonSapin Procedural macros are generally a heavy-weight solution and counting is something I've needed quite often in declarative macros (although building a |
SimonSapin
commented
Jun 29, 2017
At least building this as a procedural macro outside of the standard library would make it easier to make a case for inclusion in |
Stebalien
commented
Jun 29, 2017
Oh, I see. Good point! |
Rendered view