Return from a macro rule?

Say I have a macro like

macro_rules! any_gt {
	($v:expr $(, $es:expr)*) => {{
		$(
			if $es > $v {
				*something* true;
			}
		)*
		false
	}};
}

What can I replace the *something* with so that it stops processing and returns true?

break or return were my initial thoughts, but

  • 'break' outside of a loop, and
  • mismatched types: expected '()' because of default return type sounds like the return is actually returning from main, not the macro.

Playground

Can you wrap the body of the macro in a closure and use return?

You could use a loop and break with a value:

macro_rules! any_gt {
    ($v:expr $(, $es:expr)*) => {
        loop {
            $(
                if $es > $v {
                    break true;
                }
            )*
            break false;
        }
    };
}
1 Like

Will the closure cause any performance problems? I suppose it's possible for the compiler to optimise that case, but is it reasonable to expect that?

If so, that seems like a good solution. Otherwise loop { ... } it will have to be. I'm also wondering if either of these solutions would be considered idiomatic in rust.

What about turning it into a big if-else chain so that each branch returns a true/false?

macro_rules! any_gt {
	($v:expr $(, $es:expr)* $(,)?) => {{
	    if false { unreachable!() }
		$(
			else if $es > $v {
				true
			}
		)*
		else { false }
	}};
}

fn main() {
    assert_eq!(any_gt!(10, 1), false);
    assert_eq!(any_gt!(10, 1, 2, 3, 4, 11), true);
    
}
2 Likes

I would expect the compiler to optimize them all to roughly the same code, but that’s just a guess. Though I’m not sure if there would be any risk with loop/closure to anger the borrow checker. @Michael-F-Bryan’s solution is certainly cleaner though and easier for the compiler to optimize. I guess you could take that a step further And just do this for this case.

false $( || $es > $v )*
2 Likes

Looking back, I just found a complicated way to write if true { return true } else { return false }, didn't I? :rofl:

1 Like

with else if support, though :smile:

1 Like

Thanks all! The long boolean solution should work for my case, so I'll give that a shot.

A more general solution might be useful in other scenarios, so the loop and closure are good to know as well.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.