Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upmacro_rules! should support gensym for creating items #1266
Comments
geofft
referenced this issue
Aug 28, 2015
Closed
Types do not expand hygienically in macros that create modules #28072
This comment has been minimized.
This comment has been minimized.
|
Alternatively there could be some new macro syntax for declaring a identifier on the RHS of a macro: macro_rules! x {
() => {
$gensym a;
struct $a;
}
} |
This comment has been minimized.
This comment has been minimized.
|
To throw out another idea, clojure's syntax for gensyms is a hash after the symbol, like |
This comment has been minimized.
This comment has been minimized.
|
For the record, I think it would be really great to have this functionality in some form. |
This comment has been minimized.
This comment has been minimized.
kylewlacy
commented
Sep 1, 2015
|
+1 for the concept, although I think there's a much more sound solution: First, there'd need to be support for macros in all ident positions (see the discussion around macro_rules! x {
() => {
struct gensym!();
}
}(Although maybe this is more appropriate as a longer-term solution, following the upcoming and ever-elusive "macro reform"; in which case, I'd be fine with either of the other two syntax proposals) |
This comment has been minimized.
This comment has been minimized.
|
@kylewlacy yes, that would be better. However, as you say if every macro_rules improvement is blocked on another one, none of them will ever happen. Also, as a detail you need to be able to refer back to a gensym (for example |
This comment has been minimized.
This comment has been minimized.
|
Yeah, I've run into this many times and expected gensym from lisp languages to have been available, but it wasn't |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
|
@Stebalien is it backwards incompatible? |
This comment has been minimized.
This comment has been minimized.
|
It might be compatible if you force the metavariable to be unused on the LHS, but that's a bit of a hack |
This comment has been minimized.
This comment has been minimized.
|
Actually I'd think you would want to at least lint if you have a capture On Sat, Sep 5, 2015 at 1:42 PM, Jonas Schievink notifications@github.com
|
This comment has been minimized.
This comment has been minimized.
|
This is accepted: macro_rules! m {
( $a:item ) => ( $a# [test] fn t() {} );
}
fn main() {
m!(fn t() {});
} |
This comment has been minimized.
This comment has been minimized.
|
Yeah, you are right, I just found a similar example. On Sat, Sep 5, 2015 at 2:02 PM, Jonas Schievink notifications@github.com
|
This comment has been minimized.
This comment has been minimized.
|
Also, macro_rules! m {
( $a:ident# ) => ();
( $a:ident ) => ( m!($a#) );
}
fn main() {
m!(test);
} |
This comment has been minimized.
This comment has been minimized.
|
I feel like I'd prefer either |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
The doc point is a good one, but the question is where to put the macro_rules! m {
($a:expr) ($b:gensym) => { foo($a, $b); }
}On Sat, Sep 5, 2015 at 3:51 PM, Geoffrey Thomas notifications@github.com
|
This comment has been minimized.
This comment has been minimized.
|
Unfortunately On Sat, Sep 5, 2015 at 3:57 PM, Steven Allen notifications@github.com
|
This comment has been minimized.
This comment has been minimized.
|
Would having hygienic items solve this problem? If you write |
This comment has been minimized.
This comment has been minimized.
|
Seems like it would definitely have to be controllable somehow, because
|
This comment has been minimized.
This comment has been minimized.
|
@nrc it is not fully clear where the implicit gensyming should happen. Implicit doesn’t cover all the cases. I.e. consider macro that generates this
gensym'ing
might be desirable. |
geofft commentedAug 28, 2015
Currently
macro_rules!doesn't support the ability to generate items with unique names. This generates an error that I'm definingstruct Foomultiple times:The standard workaround is to accept an
identparameter in the macro, and name everything after that identifier somehow, even if only one item with that name is intended to be visible. lazy_static!, for instance, uses the ability of (non-tuple) structs to share a name with a value. Another option is to name a module after the ident and stuff everything inside that module. But these are incomplete workarounds: the former approach lets you create at most one type and at most one value, and the latter approach causes other hygiene problems because not everything expands the same inside a module. (For instance,typarameters don't work right because paths to types aren't necessarily valid in the module.)Having an actual gensym would solve this problem. I think you can do a simple syntax where a
macro_rules!parameter of typegensymconsumes no tokens and expands to a new, unique identifier per macro invocation, so you'd have e.g.which could still be invoked as
x! {}, but can be expanded multiple times, creating a unique structure each time. And you could do$a:gensym $b:gensymif you needed multiple names. If that's sensible, I can write this up more formally or attempt implementing it.Note that this is different from rust-lang/rust#19700: that one's about hygiene for existing items invoked by the macro, not the creation of new items. (Also I think
$crateis a sufficient workaround for that issue in practice, but doesn't help at all here.) However, the backwards-compatibility rationale in that issue applies: we can't simply gensym all literal item names in macros the way we do forlet-bindings, since that would break macros that create items with specific names. So there needs to be specific syntax for gensym.One answer is to put this off until
macro!(or whatever you want to callmacro_rules!2.0), but if this can be done simply, clearly, and backwards-compatibly, it seems worth doing now, unless the new system is happening very soon (which it doesn't seem like it is).