37

When using a macro that defines a function, is it possible to add a prefix to the function?

macro_rules! my_test {
    ($id:ident, $arg:expr) => {
        #[test]
        fn $id() {
            my_test_impl(stringify!($id), $arg);
        }
    }
}

For example, fn my_test_$id() {

I'm defining tests using an identifier which may begin with numbers, and I would like to use a common prefix.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 1
    From @skade_: here's a tracking issues discussing the nightly feature `concat_idents`, which allows that. https://github.com/rust-lang/rust/issues/29599 – ideasman42 Aug 18 '16 at 12:15
  • See also http://stackoverflow.com/q/23061702/155423; http://stackoverflow.com/q/24905160/155423; http://stackoverflow.com/q/27415011/155423. – Shepmaster Jan 21 '17 at 14:54

3 Answers3

12

Currently this is not supported in stable.


However there is a feature in nightly called concat_idents:

concat_idents!(my_test_, $id)

See

Update: it seems there aren't near-term plans to add this into stable releases, see issue.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 3
    The reason I didn't bring up `concat_idents!` is that it is, as is mentioned in that issue, *useless*. It can't be fixed; the problem is with how macros *themselves* work. No amount of work on `concat_idents!` is going to improve the situation; the macro system will have to be changed to either allow for eager re-tokenisation of AST nodes, or the compiler has to be modified to allow macros everywhere is uses names (which would be very disruptive). So even if there was an issue relevant to this problem, it wouldn't be this one. This is why I don't bother mentioning it. – DK. Jan 22 '17 at 01:38
  • 3
    Still worth bringing it up, even if only to note that it was possible / planned (but likely won't be supported). – ideasman42 Jan 25 '17 at 08:11
  • 2
    concat_idents! is awesome! You can finally add constant names to your idents inside macros. concat_idents(foo, $bar). This is essential for meta names required to perform some macro operations. Sadly it only works in nightly as of now. – Luke Dupin Mar 30 '19 at 21:14
8

[...] is it possible to add a prefix to the function?

No. Really, really no. Super totally not at all even in the slightest.

I would like to have use a common prefix.

Put them all in a mod instead.

DK.
  • 55,277
  • 5
  • 189
  • 162
  • 1
    Just to clarify, this is not possible due to [macro hygiene](https://doc.rust-lang.org/book/macros.html#hygiene), which is a feature as much as it is a limitation. – allTwentyQuestions Aug 18 '16 at 13:09
  • 3
    @allTwentyQuestions: Actually, it's a more fundamental limitation than that. Short version: in order for this to work, you would have to be able to use a macro in "identifier" position. You can't. The alternative would be to have some kind of explicit "token concatenation" *syntax*. There isn't. Hygiene doesn't really have anything to do with it. – DK. Aug 18 '16 at 13:17
  • 1
    Putting them in a module doesn't solve having first characters as numbers. – ideasman42 Aug 19 '16 at 03:36
  • @ideasman42: *Nothing* will solve having the first characters as numbers. You're just going to have to name them differently, or do the prefixing by hand. – DK. Aug 19 '16 at 03:40
  • To those who edited this answer: that's *not* an RFC, it's a tracking issue for a feature which doesn't solve this problem. – DK. Jan 20 '17 at 04:13
  • 1
    Even though this isn't in stable, thaught it worth mentioning some work has been done on this (added own answer instead of editing this one). – ideasman42 Jan 21 '17 at 20:32
  • 4
    This answer is wrong, concat_idents!() does this exact task. – Luke Dupin Mar 30 '19 at 21:22
  • https://www.youtube.com/watch?v=17KmNrG9pE4 – Martin Sep 10 '20 at 11:08
  • @LukeDupin however it sounds like that macro in practice can't actually be used to name new identifiers only refer to existing ones, because macro invocations aren't allowed in identifier position – Joseph Garvin Dec 30 '20 at 21:17
3

As mentioned, you should use submodules for this, but remember that macros can create submodules, submodules can be nested allowing their names to overlap, submodules can provide impls, and the tests submodule is not magic.

I once submitted a pull request that avoids numerous "boiler plate names" by refactoring the code using these tricks, although the #[no_mangle] exports make it harder.

Jeff Burdges
  • 4,204
  • 23
  • 46