Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for `concat_idents` #29599

Open
aturon opened this Issue Nov 5, 2015 · 67 comments

Comments

Projects
None yet
@aturon
Copy link
Member

aturon commented Nov 5, 2015

Tracks stabilization for the concat_idents macro.

@retep998

This comment has been minimized.

Copy link
Member

retep998 commented Nov 5, 2015

concat_idents is so fundamentally useless at the moment because macros cannot be used in ident positions.

@Toby-S

This comment has been minimized.

Copy link
Contributor

Toby-S commented Nov 5, 2015

Yeah it is pretty much useless right now (see #12249 #13294).

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Nov 17, 2015

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Nov 24, 2015

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 of macro_rules!, but I don't really see why you would need to use such a capability outside of a macro.

@skade

This comment has been minimized.

Copy link
Contributor

skade commented Dec 1, 2015

@skade

This comment has been minimized.

Copy link
Contributor

skade commented Dec 1, 2015

Well, given that mikkyang/rust-blas#12 is a nicer solution within the current language, I'd also like to raise my hand for "useless".

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Mar 14, 2016

I think we should never stabilise the current version - as others have noted it is useless.

@aidanhs

This comment has been minimized.

Copy link
Member

aidanhs commented May 29, 2016

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.

@retep998

This comment has been minimized.

Copy link
Member

retep998 commented May 29, 2016

Unfortunately that solution will always depend on nightly Rust (until the day that syntax extensions become stable and pigs fly).

@skade

This comment has been minimized.

Copy link
Contributor

skade commented May 30, 2016

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

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 30, 2016

@aidanhs

This comment has been minimized.

Copy link
Member

aidanhs commented May 30, 2016

@retep998 yes, just noting it as a stopgap.

@skade it's the implementation rather than the idea that's useless. If concat_idents is 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.

@skade

This comment has been minimized.

Copy link
Contributor

skade commented May 30, 2016

@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.

@aidanhs

This comment has been minimized.

Copy link
Member

aidanhs commented Jun 1, 2016

@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.

@ExpHP

This comment has been minimized.

Copy link
Contributor

ExpHP commented Nov 24, 2017

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)

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Nov 24, 2017

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.

@jonhoo

This comment has been minimized.

Copy link
Contributor

jonhoo commented Jan 14, 2018

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?

@durka

This comment has been minimized.

Copy link
Contributor

durka commented Jan 15, 2018

The RFC should be reopened. It never should have been closed, as no better solution was proposed.

@skade

This comment has been minimized.

Copy link
Contributor

skade commented Jan 15, 2018

@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.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented Jan 15, 2018

I'm with @durka on this.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented May 3, 2018

@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 (#50122), aka Span::call_site().

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 3, 2018

@durka Hygiene opt-out/escaping landing, I mean.

@durka

This comment has been minimized.

Copy link
Contributor

durka commented May 3, 2018

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 3, 2018

@durka Yeah. I feel concat_idents + early expansion + hygiene escaping is the more elegant and general solution that fits all potential use cases.

@dtolnay

This comment has been minimized.

Copy link
Member

dtolnay commented May 3, 2018

@petrochenkov currently concat_idents cannot refer to a captured local variable, only an item and items do not have 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? I would think that can happen later and does not need to be a blocker.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented May 3, 2018

@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 (or rather its minimal subset about call-site for macro invocations) is a blocker for it the same degree as for Macros 1.2 using Span::call_site in general.

@durka

This comment has been minimized.

Copy link
Contributor

durka commented May 3, 2018

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented May 3, 2018

@durka
I'd expect contexts of components to be completely lost during concatenation, it's a purely string-content based operation after all.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 3, 2018

@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 within escapes(...), this becomes a real problem.

@durka

This comment has been minimized.

Copy link
Contributor

durka commented May 3, 2018

@nrc

This comment has been minimized.

Copy link
Member

nrc commented May 3, 2018

@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.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 6, 2018

@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?

@durka

This comment has been minimized.

Copy link
Contributor

durka commented May 6, 2018

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 6, 2018

  1. or 3. sound best right now.
@dtolnay

This comment has been minimized.

Copy link
Member

dtolnay commented May 8, 2018

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! 🙂

@rfcbot fcp cancel

@rfcbot

This comment has been minimized.

Copy link

rfcbot commented May 8, 2018

@dtolnay proposal cancelled.

@alexreg

This comment has been minimized.

Copy link
Contributor

alexreg commented May 8, 2018

@dtolnay Sounds fair. Maybe we can visit this when hygiene escape support and eager expansion land, both of which I'm currently working on.

@fafhrd91 fafhrd91 referenced this issue May 12, 2018

Open

Compile with stable rust #5

5 of 6 tasks complete

AgustinCB added a commit to AgustinCB/servo that referenced this issue Sep 29, 2018

Use macro to reduce duplicated code
For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

AgustinCB added a commit to AgustinCB/servo that referenced this issue Sep 29, 2018

Use macro to reduce duplicated code
For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

AgustinCB added a commit to AgustinCB/servo that referenced this issue Oct 3, 2018

Unify the task source and task canceller API
I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

fix nits

move the tags somewhere else

AgustinCB added a commit to AgustinCB/servo that referenced this issue Oct 12, 2018

Unify the task source and task canceller API
I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

fix nits

move the tags somewhere else

AgustinCB added a commit to AgustinCB/servo that referenced this issue Nov 2, 2018

Unify the task source and task canceller API
I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

fix nits

move the tags somewhere else

AgustinCB added a commit to AgustinCB/servo that referenced this issue Nov 13, 2018

Unify the task source and task canceller API
I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)

fix nits

move the tags somewhere else

AgustinCB added a commit to AgustinCB/servo that referenced this issue Nov 14, 2018

Unify the task source and task canceller API
I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](rust-lang/rust#29599)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.