Tracking issue for concat_idents
Tracks stabilization for the concat_idents macro.
Tracks stabilization for the
concat_identsmacro.Update(fmease): Please see https://github.com/rust-lang/rust/issues/124225#issue-2255069330 (an alternative to this feature).
León Orell Valerian Liehr at 2024-04-21 14:17:29
concat_identsis so fundamentally useless at the moment because macros cannot be used in ident positions.Peter Atashian at 2015-11-05 01:45:09
Yeah it is pretty much useless right now (see #12249 #13294).
Deleted user at 2015-11-05 04:32:32
Relevant blog for future plans: http://www.ncameron.org/blog/untitledconcat_idents-and-macros-in-ident-position/
Nick Cameron at 2015-11-17 02:19:14
A solution that has been thrown around on IRC (but never ended up anywhere else AFAIK): Have a macro invocation form for "early expansion", i.e. the following would work without macros in ident position:
macro_rules! wrap { ($name:ident) => { struct concat_idents!!(Wrapped, $name)($name); } }The "early expansion"
macro_name!!(args)syntax was originally$*macro_name!(args)and is a subject of bikeshed.If we move towards having all macros produce token streams that are parsed on-demand, such "early expansion" could be used in many more locations without adding macro support for each one. Generic parameters, ADT fields, function signatures and match arms come to mind - there are so many recursive push-down hacks macros can end up with, just to construct lists of things and whatnot, that would simply not be necessary with "early expansion".
The only disadvantage is that
concat_idents!!and friends would only work inside the RHS ofmacro_rules!, but I don't really see why you would need to use such a capability outside of a macro.Eduard-Mihai Burtescu at 2015-11-24 14:39:32
https://github.com/mikkyang/rust-blas uses it for quick notation of FFI functions that follow a certain scheme: https://github.com/mikkyang/rust-blas/blob/master/src/prefix.rs https://github.com/mikkyang/rust-blas/blob/master/src/matrix/ll.rs
Florian Gilcher at 2015-12-01 07:33:50
Well, given that https://github.com/mikkyang/rust-blas/issues/12 is a nicer solution within the current language, I'd also like to raise my hand for "useless".
Florian Gilcher at 2015-12-01 11:55:57
I think we should never stabilise the current version - as others have noted it is useless.
Nick Cameron at 2016-03-14 21:49:52
Since this is the tracking issue, other who stumble across it might be interested in https://github.com/SkylerLipthay/interpolate_idents which works on nightly rust.
Aidan Hobson Sayers at 2016-05-29 20:45:35
Unfortunately that solution will always depend on nightly Rust (until the day that syntax extensions become stable and pigs fly).
Peter Atashian at 2016-05-29 21:28:14
Given that the consensus seems to be "useless" and theres nicer solutions (e.g. [1], maybe we can remove this feature?
[1] https://github.com/mikkyang/rust-blas/pull/12/files
Florian Gilcher at 2016-05-30 08:07:05
See rust-lang/rfcs#1628.
Eduard-Mihai Burtescu at 2016-05-30 08:09:02
@retep998 yes, just noting it as a stopgap.
@skade it's the implementation rather than the idea that's useless. If
concat_identsis removed rather than fixed, something else needs to fill its place (your solution doesn't work for all use-cases). I like the look of the rfc @eddyb linked, will follow that.Aidan Hobson Sayers at 2016-05-30 11:23:29
@aidanhs that still means that we should drop the feature to make sure no one uses it.
I agree that my solution doesn't cover all edge-cases, but all uses that I've currently seen in the wild. Also, but this is outside of my competence to decide, I think this is a perfect case for the use of a code generator.
Florian Gilcher at 2016-05-30 11:33:36
@skade afaict nobody can use it, so that's not a big concern...but equally there's no reason to keep it around. My main motivation for leaving it was as a reminder that people do want the functionality, but I'm content to follow the RFC and have changed my position to "I don't mind either way".
Regarding use cases, here's the motivating example that brought me to this issue in the first place. Codegen's awesome for things like phf, but it feels a bit like overkill when I just want to generate some repetitive methods to extract tuples from enum variants. I guess it's down to personal preference.
Aidan Hobson Sayers at 2016-06-01 03:06:23
An amusing fact about the current implementation of
concat_idents!is that it will accept an empty argument list, making it possible to construct the empty string as an identifier:error[E0425]: cannot find value `` in this scope --> src/main.rs:5:5 | 5 | concat_idents!(); | ^^^^^^^^^^^^^^^^^ not found in this scope(good luck actually doing anything with it)
Michael Lamparski at 2017-11-24 20:08:43
construct the empty string as an identifier
Empty string is used as a reserved identifier with special meaning in several places in the compiler, so this can potentially cause issues.
Vadim Petrochenkov at 2017-11-24 20:53:48
The linked RFC has been closed as postponed. Should
concat_idents!now be removed? Is there any chance of seeing something in its place that supports generating identifiers?Jon Gjengset at 2018-01-14 19:33:00
The RFC should be reopened. It never should have been closed, as no better solution was proposed.
Alex Burka at 2018-01-15 04:32:33
@durka I don't agree. There's ample reason to expect a new one when moving towards macros 2.0. RFCs are not necessarily closed to be replaced immediately, they are closed to stop following that line of discussion. Future RFCs might refer to it.
Florian Gilcher at 2018-01-15 15:11:05
I'm with @durka on this.
Alexander Regueiro at 2018-01-15 16:43:32
@skade I don't think much has happened regarding macros 2.0 design except for maybe some implementation experience - e.g. @jseyfried might be aware of potential issues with early expansion.
Eduard-Mihai Burtescu at 2018-01-15 16:48:26
@skade, we are moving towards macros 2.0 as far as I can tell. rust-lang/rfcs#1584 was merged (though the promised follow-ups didn't seem to come) and
#![feature(decl_macro)]exists on nightly. When is the appropriate time to reopen all the concerns that were tabled as "wait for macros 2.0"?Alex Burka at 2018-01-15 17:17:38
@eddyb @durka that is both true, my point is that this probably merits a new RFC, based on this one, except of just reopening.
Florian Gilcher at 2018-01-15 17:22:45
I implemented a stable concat_idents approach that works with any compiler >=1.15.0. https://github.com/dtolnay/mashup
David Tolnay at 2018-04-28 16:08:20
@dtolnay Black magic! Good job though. :-) Does Macros 1.2 support this yet? CC @jseyfried
Alexander Regueiro at 2018-04-28 22:30:06
Does Macros 1.2 support this yet?
If Macros 1.2 added support for any form of early expansion, everybody would know about it. I mean, it'd make international news.
Michael Lamparski at 2018-04-28 22:53:26
Hah. I know it was being discussed properly at one point... guess it never got too far!
Alexander Regueiro at 2018-04-28 22:56:21
I would like to propose stabilizing
concat_idents!as it currently exists. As discussed at length in this thread,concat_identsdoes not solve all use cases for concatenated identifiers especially as a consequence of no macro expansion in identifier position. Nevertheless, this macro does a useful thing and has its uses for putting together certain types of convenient APIs.Basically I don't feel the need to push for macro expansion in more places before stabilizing use of
concat_identsin expression position.For more elaborate use cases of concatenated identifiers I believe directing people to use
mashupis acceptable.@rfcbot fcp merge
David Tolnay at 2018-05-02 23:38:00
Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged teams:
- [ ] @Kimundi
- [ ] @SimonSapin
- [x] @alexcrichton
- [ ] @aturon
- [ ] @cramertj
- [x] @dtolnay
- [ ] @eddyb
- [ ] @joshtriplett
- [ ] @nikomatsakis
- [ ] @nrc
- [ ] @pnkfelix
- [ ] @scottmcm
- [ ] @sfackler
- [ ] @withoutboats
Concerns:
- naming (https://github.com/rust-lang/rust/issues/29599#issuecomment-386177757)
Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!
See this document for info about what commands tagged team members can give me.
Rust RFC bot at 2018-05-02 23:38:00
Without necessarily objecting to this: how difficult would it be to modify the existing
concat_idents!in rust to have the functionality that people desire? I realize that doing so does require unstable compiler features to implement, but so do many other stable interfaces in the Rust standard library.Josh Triplett at 2018-05-03 00:20:59
Stabilization? This? Really?
Uhh, in that case, I guess I'll throw up a PR to fix the empty identifier bug (since I basically found it by looking at the source code).
Michael Lamparski at 2018-05-03 00:30:29
@dtolnay Sounds reasonable. Using it in identifier places can come when my PR for hygiene escaping lands. :-)
Alexander Regueiro at 2018-05-03 00:52:53
Maybe with a big banner in the docs saying "this probably isn't what you want!!!" and pointing to mashup.
On Wed, May 2, 2018 at 8:30 PM, Michael Lamparski notifications@github.com wrote:
Stabilization? This? Really?
Uhh, in that case, I guess I'll throw up a PR to fix the empty identifier bug (since I basically found it by looking at the source code).
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386161726, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n7oAQwOdgziD9t24XKIwm4chVRPlks5tuk-7gaJpZM4GcPel .
Alex Burka at 2018-05-03 00:54:02
@joshtriplett What do you mean? This macro can't be implemented in a library, it's already built-in. However, macro invocations are not allowed in identifier positions which simplifies many things (how do you parse a macro invocation when its name could be produced by another macro?), and this is where "early expansion" comes in, because then you're "just" expanding arbitrary tokens, not ASTs.
Eduard-Mihai Burtescu at 2018-05-03 00:56:09
@joshtriplett I don't think
concat_identsis at fault, really. The issue is that macros can't be expanded in certain positions. Something would have to change around that, or around eager expansion, to be able to useconcat_identsfor something like constructing the names of getter/setter functions. The other issue is hygiene, but that is going to be fixed with proc macros in another way (punted for now).Alex Burka at 2018-05-03 00:58:10
@eddyb Ah, I thought it was just a hygiene problem... Looks like it's a hygiene and early-expansion problem.
@durka Yep, I'm working on the hygiene part. We've got what seems like a pretty good approach now, but we're actually going to implement two and feature-gate them, then experiment with them.
Alexander Regueiro at 2018-05-03 01:08:21
Perhaps change the name to reflect that it probably isn't what you want?
On Wed, May 2, 2018, 8:08 PM Alexander Regueiro notifications@github.com wrote:
@eddyb https://github.com/eddyb Ah, I thought it was just a hygiene problem... Looks like it's a hygiene and early-expansion problem.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386166687, or mute the thread https://github.com/notifications/unsubscribe-auth/AIazwBfVVTrITMp1JxyJRqj7XjOVYs3Cks5tulidgaJpZM4GcPel .
mark at 2018-05-03 02:13:41
Is there a reason why it can't be used in patterns?
error: non-pattern macro in pattern position: concat_idents --> src/main.rs:3:9 | 3 | let concat_idents!(fn) = 4; | ^^^^^^^^^^^^^Michael Lamparski at 2018-05-03 02:26:41
Oh and FYI you can construct keywords as identifiers, too =P
Edit: I'm dumb, that's probably intentional for the sake of raw identifiers
Michael Lamparski at 2018-05-03 02:28:47
@rfcbot concern naming
Practically every use I've had for
concat_identshas required being able to use macros in identifier position, so if I discovered a stable macro calledconcat_identsI'd certainly expect this to work. Can we come up with a better name for the macro that is suggestive of its limited usability, while also leaving the door open to a macro that "does what you want" such asmashupbeing calledconcat_idents!?Taylor Cramer at 2018-05-03 02:39:14
The macro does what it says on the tin - it concatenates idents. The changes required to make it work in positions it doesn't yet aren't in the macro, they're in the rest of the compiler.
Steven Fackler at 2018-05-03 02:43:06
@cramertj
mashupis a big hack, right now, as I see. Anyway, it's a 3rd-party crate, and I don't see why we should be concerned about official Rust identifiers clashing with 3rd-party ones. Once eager-expansion and hygiene land, it will do what we all want.Alexander Regueiro at 2018-05-03 02:45:03
@sfackler if that was directed to me, pattern macros already exist.
If not, uh... carry on!
Michael Lamparski at 2018-05-03 02:45:44
I'm not confident eager expansion is coming, and not sure what "hygiene landing" means.
On Wed, May 2, 2018 at 10:45 PM, Alexander Regueiro < notifications@github.com> wrote:
@cramertj https://github.com/cramertj mashup is a big hack, right now, as I see. Anyway, it's a 3rd-party crate, and I don't see why we should be concerned about official Rust identifiers clashing with 3rd-party ones. Once eager-expansion and hygiene land, it will do what we all want.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386178433, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n0wf8OBy8BAikrBCnRaLx2l2iqUZks5tum9IgaJpZM4GcPel .
Alex Burka at 2018-05-03 02:46:31
Are there actual uses that can't be replaced by mashup? Mashup is a hack for now, but it should be fine once function-like proc macros land.
Unscientifically, from the first page of the search results @dtolnay linked, 7 repos don't actually use the macro (presumably they added the feature and then discovered it was useless).
Maybe concat_idents is tantalizing but useless and should be deprecated.
On Wed, May 2, 2018 at 10:46 PM, Michael Lamparski <notifications@github.com
wrote:
@sfackler https://github.com/sfackler if that was directed to me, pattern macros already exist.
If not, uh... carry on!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386178524, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n01QOGA8R2UaJrcUTzzWB5qmAJUpks5tum9vgaJpZM4GcPel .
Alex Burka at 2018-05-03 02:53:10
I'd love to see someone do a demonstration where they adjust
winapi's macros to usemashupand eliminate the redundant inputs I have to specify due to the lack of a usefulconcat_idents.Peter Atashian at 2018-05-03 03:35:39
@eddyb I can understand not being able to produce a macro invocation with a macro, for instance. But why does that prevent, for instance, generating the name of a function or variable?
Josh Triplett at 2018-05-03 05:31:13
Sorry about the search results @durka, obviously :broken_heart: GitHub search. I clicked through the first 8 pages and found the following diverse and wonderful use cases. These crates are using concat_idents because it does exactly what is needed for their situation. I am happy to dig through all 27 pages if this does not change your mind about the macro being "tantalizing but useless and should be deprecated."
I believe
concat_idents!is a valuable building block for macros, much likestringify!, despite not solving everybody's use cases all the time.
-
stringify!($func_name) => mem::transmute::<concat_idents!(PFN_, $func_name), _>(Some(*&$func_name::<I>)), -
concat_idents!($prefix, _callback_, $event)($core, concat_idents!(on_, $event), $tx); -
transmute(concat_idents!($pre, $name, $post)( $( transmute($arg) ),* )) -
(Complex64, $f: ident) => (concat_idents!(z, $f)); -
concat_idents!(hyperdex_client_, $fn_name)(*inner_client.ptr, -
concat_idents!(read_, $quote, _string_character)($ts, $string_chars_pos, $buff)?; -
(1 s $x:ident) => (Typed::Single(Box::new(concat_idents!(d1_s_, $x)()))); -
unsafe { Value::new_unchecked(concat_idents!(jl_box_, $t2)($fn)) } -
unsafe { concat_idents!($thname, _retain)(self.t)}; -
unsafe { f128::from_arr(concat_idents!($sm, _to_f128)(small)) } -
concat_idents!(blend_function_, $name)() -
let f = concat_idents!(Uniform1, $suffix); -
($id: ident) => { unsafe { concat_idents!(per_lcore_, $id) } }; -
match concat_idents!($callback, _impl)(
David Tolnay at 2018-05-03 06:30:53
-
Through page 13:
-
defsubr(concat_idents!(S, $f).as_ptr()); -
#[test] fn in_() { test(concat_idents!($name, _in)); } -
let error_code = concat_idents!($ffi_prefix, $name)($field$($other_fields)*, result); -
((($x) >> concat_idents!($name, _SHIFT)) & concat_idents!($name, _MASK)) -
unsafe { $name { ir : concat_idents!(FAST, $name, New)() } } -
raw_builder: *mut concat_idents!(Raw, $builder_name) -
virt_addr >= & concat_idents!(__, $n, _start) as *const u8 as usize &&
David Tolnay at 2018-05-03 06:42:57
-
-
let raw_fn = concat_idents!(cmark_node_get_, $prop); -
concat_idents!(unqlite_kv_cursor_, $i)($($e),*) -
pub unsafe fn raw(&self) -> concat_idents!($prefix, Ptr) { -
let mapper = concat_idents!(nodup_, $v); -
let sec = (concat_idents!(archive_entry_, $apiname))(self.entry);
David Tolnay at 2018-05-03 06:51:24
-
@rfcbot concern: Audit hygienic context of the produced identifier, add relevant tests
Context of the ident should probably be the context of
concat_idents!macro invocation (https://github.com/rust-lang/rust/issues/50122), akaSpan::call_site().Vadim Petrochenkov at 2018-05-03 10:07:15
@durka Hygiene opt-out/escaping landing, I mean.
Alexander Regueiro at 2018-05-03 13:12:24
OK, that's a lot more uses than I thought! I guess it's hard to replace them all with mashup because you'd have to generate so many macros?
On Thu, May 3, 2018, 09:12 Alexander Regueiro notifications@github.com wrote:
@duroa Hygiene opt-out/escaping landing, I mean.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386290569, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n3SwnrGXRRIvhOjPm6wStlrGBXBOks5tuwJWgaJpZM4GcPel .
Alex Burka at 2018-05-03 16:28:59
@durka Yeah. I feel
concat_idents+ early expansion + hygiene escaping is the more elegant and general solution that fits all potential use cases.Alexander Regueiro at 2018-05-03 16:53:16
@petrochenkov currently
concat_identscannot refer to a captured local variable, only an item and items do not have hygiene. Do you thinkconcat_identsis different enough from other cases of non-atomic code fragments that we need to block stabilization until the non-atomic hygiene story is worked out? I would think that can happen later and does not need to be a blocker.David Tolnay at 2018-05-03 17:37:31
@dtolnay
currently concat_idents cannot refer to a captured local variable
That's a bug.
and items do not have hygiene.
All identifiers have hygiene with macros >= 1.2!
concat_identslooks like a typical use case forSpan::call_sitehygiene.Do you think concat_idents is different enough from other cases of non-atomic code fragments that we need to block stabilization until the non-atomic hygiene story is worked out?
concat_identsis not special, #50122 (or rather its minimal subset about call-site for macro invocations) is a blocker for it the same degree as for Macros 1.2 usingSpan::call_sitein general.Vadim Petrochenkov at 2018-05-03 17:55:00
What should happen with concat_idents!($a, $b) when $a and $b come from different hygiene contexts?
On Thu, May 3, 2018 at 1:55 PM, Vadim Petrochenkov <notifications@github.com
wrote:
@dtolnay https://github.com/dtolnay
currently concat_idents cannot refer to a captured local variable
That's a bug.
and items do not have hygiene.
All identifiers have hygiene with macros >= 1.2! concat_idents looks like a typical use case for Span::call_site hygiene.
Do you think concat_idents is different enough from other cases of non-atomic code fragments that we need to block stabilization until the non-atomic hygiene story is worked out?
concat_idents is not special, #50122 https://github.com/rust-lang/rust/issues/50122 (or rather its minimal subset about call-site for macro invocations) is a blocker for it the same degree as for Macros 1.2 in general.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386381912, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n8i0Von0gNWwefFkN6Z9NQOoOqFeks5tu0SUgaJpZM4GcPel .
Alex Burka at 2018-05-03 18:02:24
@durka I'd expect contexts of components to be completely lost during concatenation, it's a purely string-content based operation after all.
Vadim Petrochenkov at 2018-05-03 18:13:27
@durka I'd expect the same as @petrochenkov. The identifier would then take the syntax context of its call site (i.e. where it's used in code), unless escaped (e.g. using
#syntax). We have discussed the#[escapes(...)]approach to escaping hygiene as well, but unless we allow macro expansion withinescapes(...), this becomes a real problem.Alexander Regueiro at 2018-05-03 18:23:04
OK, that makes sense. I just remember that being a question that came up around this macro before.
On Thu, May 3, 2018 at 2:23 PM, Alexander Regueiro <notifications@github.com
wrote:
@durka https://github.com/durka I'd expect the same as @petrochenkov https://github.com/petrochenkov. The identifier would then take the syntax context of its call site (i.e. where it's used in code), unless escaped (e.g. using # syntax). We have discussed the #[escapes(...)] approach to escaping hygiene as well, but unless we allow macro expansion within escapes(...), this becomes a real problem.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386390784, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n0lFw5QraOUxg9z5wJVGp2ANhu8Cks5tu0sigaJpZM4GcPel .
Alex Burka at 2018-05-03 18:32:50
@concern premature
I don't think we should stabilise concat_idents, between the macro system and the macro itself, this is not the macro that most macro authors want, but it is occupying prime naming real estate. I would prefer to wait until we have a macro that does do what people want before stabilising something.
Is there a strong reason to stabilise this now when we've been OK without stabilising it for years? It does seem like a really sub-optimal thing to stabilise.
Nick Cameron at 2018-05-03 22:34:14
@nrc It does what it says on the tin though, as has been pointed out. Shouldn't the aim just be to work on early (eager) expansion now?
Alexander Regueiro at 2018-05-06 16:13:39
So the main issue with "it doesn't do what macro authors want" is that it only works in expressions, right? It doesn't work for defining things because macros aren't accepted in ident position. Some possible mitigations:
-
Just make that extremely clear in the documentation
-
Change the name somehow to reflect it (concat_idents_for_expr? make_expr_name?). If eager expansion actually happens the name would be awkward, but we could deprecate and change the name back in that case.
-
Make the error message better when discovering a macro invocation in ident position (currently it's just unexpected
!with no notes or helps)
On Sun, May 6, 2018 at 12:14 PM, Alexander Regueiro < notifications@github.com> wrote:
@nrc https://github.com/nrc It does what it says on the tin though, as has been pointed out. Shouldn't the aim just be to work on early (eager) expansion now?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/29599#issuecomment-386890599, or mute the thread https://github.com/notifications/unsubscribe-auth/AAC3n4JGRm5swlmIdV-0ryEkiAjWQU1yks5tvyFKgaJpZM4GcPel .
Alex Burka at 2018-05-06 17:13:31
-
- or 3. sound best right now.
Alexander Regueiro at 2018-05-06 17:27:40
I continue to believe this macro in its current form serves as a valuable building block for API design despite being limited to solving a specific set of use cases and not them all. There comes a time in an experienced macro author's life when they have seen many dozen situations that require exactly this functionality and wonder what the holdup could be after almost 7 years. But I can see that changing so many minds is not going to be a good use of two teams' time. Thanks for the discussion everyone! :slightly_smiling_face:
@rfcbot fcp cancel
David Tolnay at 2018-05-08 15:53:16
@dtolnay proposal cancelled.
Rust RFC bot at 2018-05-08 15:53:16
@dtolnay Sounds fair. Maybe we can visit this when hygiene escape support and eager expansion land, both of which I'm currently working on.
Alexander Regueiro at 2018-05-08 23:20:42
has there been any movement on being able to use this in definitions?
snek at 2019-09-14 19:06:17
@devsnek nope, most use cases can be solved by using https://github.com/dtolnay/paste though.
Taylor Cramer at 2019-09-23 23:39:39
@cramertj will that allow
fn concat_idents!(x, y)() {}? If so that's great, but it still feels like concat_idents not working on identifiers in definition positions is an abstraction leak of however the parser works.snek at 2019-09-24 00:23:16
@devsnek
concat_identsbasically does not work, and there is no intention to stabilize it as it exists today.Taylor Cramer at 2019-09-24 16:24:29
I also had that problem and just wrote and published a crate that provides a working solution: https://crates.io/crates/concat-idents https://github.com/DzenanJupic/concat-idents
The syntax is a bit different from the std-solution:
concat_idents!(<IDENT> = <IDENT1>, <IDENT2>, <IDENT3>, [...] { // --snip-- });But it works and can be used to, for example, generate tests:
macro_rules! generate_test { ($method:ident($lhs:ident, $rhs:ident)) => { concat_idents!(test_name = $method, _, $lhs, _, $rhs { #[test] fn test_name() { let _ = $lhs::default().$method($rhs::default()); } }); }; } #[derive(Default)] struct S(i32); impl Add<i32> for S { type Output = S; fn add(self, rhs: i32) -> Self::Output { S(self.0 + rhs) } } impl Sub<i32> for S { type Output = S; fn sub(self, rhs: i32) -> Self::Output { S(self.0 - rhs) } } generate_test!(add(S, i32)); generate_test!(sub(S, i32));In this case, the last two lines would expand to:
#[test] fn add_S_i32() { let _ = S::default().add(i32::default()); } #[test] fn sub_S_i32() { let _ = S::default().sub(i32::default()); }As long as the resulting identifier is valid, you can use a combination of identifiers, underscores, integers, and booleans. Currently, it's not possible to define multiple identifiers in one macro call, but I'll add this feature soon.
I would love to hear your feedback :)
Dzenan Jupic at 2020-08-04 16:44:04
I also had that problem and just wrote and published a crate that provides a working solution: https://crates.io/crates/concat-idents https://github.com/DzenanJupic/concat-idents
That sounds very similar to the paste crate
Sebastian Dröge at 2020-08-04 16:50:27
Is there a way to use this but with a type
ty? Perhaps by extracting theidentfromty? But I can't find a way to do that in amacro_rules.David Wong at 2021-10-01 20:58:44
Once a
macro_rules!macro parses a token as anything other thanttoridentit becomes completely opaque. If you need to do something more complicated like get theFoofromFoo<A, B>then you should consider writing a proc macro and using thesynandquotecrates.(or if it's a macro for internal use, you can always settle for some subset of type syntax that's easier to parse, e.g.
$name:ident<$($param:ty),*>)Michael Lamparski at 2021-10-02 15:14:06
If we were to keep/stabilize this, it would need to work in the fashion people expect it to work (in place of an identifier).
Josh Triplett at 2021-11-10 19:01:17
I'd like for this to also support concatenating with integer literals, e.g.
const MY_CONST1: u32 = 1; const MY_CONST2: u32 = 2; concat_idents!(MY_CONST, 2)Markus Reiter at 2022-09-20 16:02:26
This is especially useful for embedded when we have many names we do not have control over. (register names) where most of the difference is a number.
Alexis Paques at 2023-02-02 18:09:22
It would be nice if we could use
concat_idents!would optionally acceptself.as first argument. This would allow accessing member variables and functions.David Kleingeld at 2023-06-01 13:36:44
@dvdsk, I think this is already covered by https://github.com/rust-lang/rust/issues/29599#issuecomment-1572068214. If the macro works in
identpositions, I assume you can simply use e.g.self.concat_idents!($field, 0).Markus Reiter at 2023-06-01 18:28:26
@dvdsk, I think this is already covered by #29599 (comment). If the macro works in
identpositions, I assume you can simply use e.g.self.concat_idents!($field, 0).Ah I thought 'ident positions' referres to things like
fn concat_idents!(macro_args)(function args) { ... }. Of course self can also be followed by anidentso its also an ident position.Reading the rust reference the dot symbol (
.) can currently only be followed by Field access or Tuple index. Not by a macro invocation. I think macro invocations need to be preceded by whitespace, I am no expect on Rust syntax however.On a separate note
self.macromight be confusing, one might think that syntax means calling a member macro? I would proposeconcat_idents!(self, test)resolving toself.test.Finally self is not an ident but a keyword. So strictly speaking concat_idents should not cover it. So maybe we should drop
concat_idents!and add aconcatmacro or look at https://github.com/rust-lang/rust/pull/111930.David Kleingeld at 2023-06-01 20:52:28
Three comments:
- What are the problems with stabilizing this as-is and later adding the expected features? This does not seem to conflict anywhere.
- Are there problems with special casing this macro to allow only its use in the identifier position? Even only within other macros, so that the relationship between
macro_rules!andconcat_idents!is about the same aspaste!and paste's[<...>]syntax. Obviously this would not be trivial to implement... - This should be able to unstringify string literals,
concat_idents!(foo, "bar")->foobar(aspastedoes), for macros where it is logical for a user to specify a string but an identifier needs to be created from it
Trevor Gross at 2023-10-08 07:45:34
From the docs:
Also, as a general rule, macros are only allowed in item, statement or expression position. That means while you may use this macro for referring to existing variables, functions or modules etc, you cannot define a new one with it.
Is there any particular rationale for disallowing identifier concatenation in the definition of items? I really hate using
paste.Sylv at 2023-11-02 02:29:24
It’s not that they’re excluded explicitly. It’s the other way around: parts of the language that expect an item, statement, or expression each accept various kinds of syntax, one of which being a macro invocation. In parts of the language that expect an identifier, the syntax is more restrictive (only accepting a plain or raw identifier token).
Accepting a macro invocation everywhere an identifier is accepted would be tricky at best because macro invocations themselves start with an identifier.
pasteadds dedicated[<…>]syntax specifically to avoid these ambiguities. Maybe accepting a macro invocation in a few more specific places like the name of anfnitem is possible, I don’t know. I suspect even coming up with a concrete and plausible proposal would take some work.Simon Sapin at 2023-11-02 05:57:35
What about having
concat_identsbe a reserved word in Rust 2024? That would eliminate the ambiguity, becauseconcat_idents!would no longer be a macro. Instead, it would be dedicated syntax that merely appeared to be a macro.Of course, this might cause parsing problems. In particular, I doubt it would be compatible with an LALR(1) or LR(1) grammar.
Demi Marie Obenour at 2023-11-02 16:47:25
At this point it would probably be better to implement ident concatenation as a "metavariable expression", like
${concat_idents(a, b, c)}or something.Then in a code produced by
macro_rulesand parsed by Rust parser it will already be represented as a single identifier, so it will work in any position.Vadim Petrochenkov at 2023-11-02 16:52:59
I think it would be nice to have something like
${concat_idents(a, ${concat_idents(b, c)}), i.e., a mechanism to eagerly evaluate a metavariable expression.Caio at 2023-11-02 17:41:47
I'm sure there is a good answer but I don't see it here - why do we need
concat_identsas a standalone macro in the first place? In theory it should be possible to have macro bodies have a syntax that concatenates things, likefoo_##barin C macros or[<foo_ $bar>]inpaste. I guess this is in line with the metavar idea.Also, it is extremely helpful to be able to convert between upper, lower, snake, and camel cases identifiers in paste. I sure wouldn't mind having this in std somehow if there were a good syntax...
Trevor Gross at 2023-11-18 02:47:12
🚀 I found a way to evaluate
concat_idents(andconcatand few other built-in macros) before evaluating other macro, which takesconcat_identsas an argument! I. e. I found a way to evaluatea!(concat_idents!(...))such way, thatconcat_identsevaluates beforea. Answer is crate https://crates.io/crates/with_builtin_macros !!! In other words,with_builtin_macrosispaste, but not only forconcat_idents, but also forconcatand some other macros.And in other words,
with_builtin_macrosallows one to achieve eager evaluation of macros in limited way.Also,
with_builtin_macrosallows one to useconcat_identswhen defining new identifier.Also, https://crates.io/crates/with_builtin_macros allows one to use
concat_identsin stable Rust.// (This code was not tested, may contain typos) fn concat_idents!(a, b) () {} // Doesn't work with_builtin_macros::with_eager_expansions! { fn #{ concat_idents!(a, b) } () {} // Works! Even on stable! } macro_rules! this_macro_accepts_ident { ($a:ident) => {} } this_macro_accepts_ident!(concat_idents!(a, b)); // Doesn't work, because "this_macro_accepts_ident" evaluates before "concat_idents" with_builtin_macros::with_eager_expansions! { this_macro_accepts_ident!(#{ concat_idents!(a, b) }); // Works! Even on stable! }Askar Safin at 2024-10-13 02:09:33