Skip to content
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

Allow macros to determine the length of multiplicative arguments #12782

Closed
ghost opened this issue Mar 9, 2014 · 3 comments
Closed

Allow macros to determine the length of multiplicative arguments #12782

ghost opened this issue Mar 9, 2014 · 3 comments
Labels
A-syntaxext Area: Syntax extensions

Comments

@ghost
Copy link

ghost commented Mar 9, 2014

This would allow http://static.rust-lang.org/doc/master/std/macros/macro.vec.html to use Vec::with_capacity to avoid unnecessary reallocations of the vector.

I'll be happy to take this on but I'm not entirely sure what a good syntax for this would be. I was thinking of:

macro_rules! vec(
    ($($e:expr),*) => ({
        // leading _ to allow empty construction without a warning.
        let mut _temp = ::std::vec_ng::Vec::with_capacity(#($e));
        $(_temp.push($e);)*
        _temp
    })
)

Since the individual elements in a multiplicative pattern can contain an arbitrary tree of expressions, # would recursively count all the elements that would expand to a specific $identifier.

@huonw
Copy link
Member

huonw commented Mar 9, 2014

I like this idea.

Note a version of this is currently possible with a recursive macro:

macro_rules! count_expr {
    () => { 0 };
    ($_e: expr $(, $rest: expr)*) => { 1 + count_expr!($($rest),*) }
}

Of course, this is slow (possibly even O(n^2), due to some implementation details/bugs), and a separate version of this is needed for every possible non-terminal, e.g. the expr one can't (easily) be reused to count items.

That said, I have wanted a macro/thing like this rather than the count_expr hack, but I think there are some subtleties to consider, e.g.

macro_rules! foo {
    ( $( $( $e: expr ),* );* ) => {
        (#( $($e)* ), 
         #($e))
    }
}

foo!(1, 2, 3; 4, 5, 6, 7) // == (2, 7) ?
  • is #($e) at the top level valid (i.e. when $e has two levels of repeats)? if so, what does it count? (the total number of $e's across all copies of the outer repeat? )
  • is #($($e)) valid as a way to count the number of exterior repeats?

Also, I don't quite understand

Since the individual elements in a multiplicative pattern can contain an arbitrary tree of expressions, # would recursively count all the elements that would expand to a specific $identifier.

could you explain it with an example?

@ghost
Copy link
Author

ghost commented Mar 9, 2014

@huonw What I meant is exactly your first bullet point. That, in your example, it should count "the total number of $e's across all copies of the outer repeat".

is #($($e)) valid as a way to count the number of exterior repeats?

I think so. An alternative would be to allow you to bind a whole sequence of items to an identifier:

macro_rules! foo {
    ( $( $outer( $e: expr ),* );* ) => {
        (#($outer), 
         #($e))
    }
}

Not sure if that would create any ambiguity in the syntax.

@alexcrichton
Copy link
Member

My relevant comments are here: #12916 (comment), we've decided that this should go through the official RFC process now that we have one in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-syntaxext Area: Syntax extensions
Projects
None yet
Development

No branches or pull requests

2 participants