Announcing mashup: a stable implementation of concat_idents

The nightly-only concat_idents! macro in the standard library is notoriously underpowered in that its concatenated identifiers can only refer to existing items, they can never be used to define something new.

I combined together all the macro trickery I have ever used and came up with a macro called mashup! which implements a stable flexible approach to concatenating idents. It works on any Rust version >= 1.15.0.

Check out the readme for a more realistic example but the basic idea is as follows.

extern crate mashup;

// Use mashup to generate a substitution macro called m. The substitution macro
// will replace all occurrences of the key token "method" in its input with the
// single concatenated identifier abc.
mashup! {
    m["method"] = a b c;

struct Struct;

m! {
    impl Struct {
        fn "method"() {}

fn main() {
    // Our struct now has an abc method.

Awesome that ident concatenation is now possible in stable rust!

One question from someone looking at this from the outside though: Is there a specific reason to conflate search/replace functionality with ident concatenation?

Generating a search/replace macro is the only stable way I know of to have the effect of ident concatenation, so if you write a macro designed for ident concatenation then it will necessarily be doing a search/replace step.

It would be possible to implement the API of the unstable interpolate_idents crate on top of mashup + proc-macro-hack by writing a procedural macro that expands to the appropriate mashup invocation. It would be more convenient in a way but less convenient in that you would need separate entry points if your macro expands to an expression vs to an item, and it would not be possible to support type macros and pattern macros at all that way.

In the end I felt that letting the user place the mashup invocation where it makes sense in their code is a flexible and convenient approach with the smallest number of limitations.

1 Like

FWIW, I find interpolate_idents! pretty trivial to use, while after trying to use mashup! in for ~1 hour I actually gave up. I must be missing something fundamental about how mashup! works because I really wasn’t able to replace any single one of the interpolate_idents! uses in that library :confused: