-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add std::function_name macro for getting the name of the current function #1719
Conversation
I would also open to implementing this myself btw, from a short look it seems like all information required might already be available in libsyntax/ext/source_util.rs. The CodeMap mentions callees and callsites, but without looking closer I'm not sure if this only applies to macros calling macros. |
`std::file`. It would return the fully qualified function name, which would be | ||
the same as seen with `RUST_BACKTRACE=1`, e.g. | ||
|
||
- `hello::main::h14dbb225e6ef2d49` for function `main` crate `hello` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems... less than good? Why are we trying to give this information. I'd much rather know just the fully qualified function name:
hello::main
hello::bar::foo
hello::bar::Foo::new
hello::bar::Foo<T>::new
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be without the hash, and otherwise only make a difference for cases with generic parameters? I'll add this to the unresolved questions, thanks for the feedback!
Intuitively I also prefer this, but there was probably a reason for not doing this for backtraces and consistency also seems useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backtraces are implementation defined; this is not :)
Backtraces are based on the name you'd call this function in C or assembly, with mangling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know, that convinces me that this is a better scheme indeed. I'll update the RFC accordingly
I want it to use the "real" qualified function name, but otherwise I really really want this. |
So, question: Do you see struct Foo<T>;
impl Foo<T> {
fn new() { }
}
fn main() {
struct T;
Foo::<T>::new() <- here
Foo::<u32>::new() <- or here as well
} |
That would actually depend on the details. But IMHO it should return exactly what you see in the code where the std::function! was inserted, i.e. in your case Does that make sense? I should clarify that, if it does |
@sdroege Definitely clarify. Also, remember, |
Thanks noticing that, I'll update it on Monday. Also I noticed that trait implementations need to be handled too. Any preference for those? |
@sdroege Personally, how you'd call them, so I don't know, tho :P, whatever you think is right :) |
Getting the fully qualified name of the current function would actually be easier to implement, even if more invasive, than doing it during macro expansion. |
One advantage of an intrinsic is that you're not polluting the global namespace. If it's possible for there to be such thing as a stable intrinsic, I would personally prefer that approach. If this needs to be a macro, it should probably be called |
I'd recommend |
- Call the macro `function_name` to make conflicts with other macros less likely, make the name an "Unresolved Question" and mention in "Drawbacks" that adding a new macro takes it away from the global namespace - Don't include the `module_path` anymore, it seems easy enough to just use the corresponding macro for that in addition if it is needed - Clarify how the function names would look like in the context of generic functions, various types of `impl` blocks and closures - Add naming of closures to "Unresolved Questions" - Add suggestion of using an intrinsic instead of a macro to "Unresolved Questions"
bda3a0e
to
6c14afe
Compare
Thanks for all the comments. I've updated the text now to include all your suggestions, please take a look again and let me know what you think. A small changelog is in the commit message |
Regarding closures, here are a few alternatives for naming closures:
My favorite is alternative 2, and it wouldn't be too hard to implement. It could be combined with 3. for multiple closures on the same line, but that seems like a tiny share of all use cases. |
@Centril I think closure names should be implementation defined - mainly because I'd like it if rustc someday applied heuristics to generate 'smart' closure names like Actually, is there really much disadvantage to having names be implementation defined in general? There are other simplifications that might be nice to apply to long generic names, but would be hard to specify precisely. For example:
|
@Centril 2) is actually a very good idea, thanks. I'll update that accordingly soon. @comex I would consider all these strings as not-set-in-stone. They are for guiding the user where to find the corresponding code (or more exact to get some idea what that code is doing without looking it up), they are not meant for automatic processing. As such, I could probably say in the RFC that the actual strings are implementation defined, clarify a bit more what they're good for and what not, and give some examples (i.e. how the first implementation will look like). Does that make sense to you? @comex About your other comments, they make sense but seem a bit tricky to implement. I would leave that for later times. Especially the first one is an interesting point. |
…mples Also let the closure example include the line number of definition as suggested in the PR.
Done so now. Any other feedback? How should this move forward? |
I think I would like this RFC to at least mention nested functions, ie something like in this (very contrived) example: fn main() {
let foo = || {
if 1 == 1 {
fn bar() {
println!("{}", function!())
}
bar();
} else { // EDIT: else case added
fn bar() {
println!("{}", function!());
}
bar();
}
};
foo();
} Edit: (Added the |
Thanks, I'll add something along those lines. Nested functions should probably be treated like closures in that regard, but including their actual name |
I've mentioned nested functions too now, thanks again |
} | ||
```` | ||
|
||
- Similar for generic `impl` blocks, e.g. `SomeStruct<T>::some_function` for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this outputs generic version, rather than monomorphisation?
I feel that looking at prior art is an important factor in making decision here. I’ve already pointed out the behaviour of C/C++ macros here. I since have remembered using a similar debug format in my python project: What are other languages which provide a way to log function name for debugging purposes? Do they have a way to log the full path to the function? If yes, how often is it used by the users of the language (as opposed to the method to log just the function name, if there’s also a way to do that)? Do any of these languages include type parameters? If yes, why? Regardless of prior art, I strongly suggest to abandon any attempts to uniquely identify any function by its name (or simply use UFCS). |
A type alias that represented the return type of the current function might be useful too. |
ping @rust-lang/libs (on behalf of @ubsan), anyone got opinions on this one? Want to move it forward? |
Sorry for not having any progress here in the last weeks, it's still on my list but other things got into the way. If someone else wants to move it forward, please go ahead. This also is relevant for slog, e.g. https://github.com/slog-rs/slog/blob/9ec2bc5286c273fe7c0df7dd29c4f23f1ef9c705/src/lib.rs#L307 just uses "" as the function name currently. |
The libs team discussed this RFC during triage. The motivation generally seems compelling, and we'd love to see something like this land. It seems to've stalled out a bit, though. I'm going to go ahead and close the RFC, for the sake of clearing the queue, but @sdroege (or anyone else) should feel free to reopen with revisions accounting for the discussion on thread. |
Is there any progress on this? |
Not really, for myself I've postponed this for now as there are more urgent things to work on. Having this solved would nonetheless be nice, just that coming up with a meaningful and short scheme for "function name" is far from trivial. |
Why try to find a silver bullet? Create a macro that accepts arguments, and let the user figure out what they want. This is a stab at the idea (please forgive any errors, I started learning rust ~4 weeks ago): enum FuncInfoOptions {
Name,
Path,
GenericArgumentList, // Generic arguments before being specialized to concrete types
ConcreteArgumentList,
GenericReturnType,
ConcreteReturnType,
... // Whatever other options people think might be useful.
}
macro_rules! funcInfo() {
// Here there be magic incomprehensible to Mortal Man,
// or at least Man with <= 4 weeks of rust experience.
}
fn myFunc() -> () {
println!("This function is named: {}", funcInfo!(Name));
println!("This is the generic signature of this function: {} {}::{} {}", funcInfo!(GenericReturnType), funcInfo!(Path), funcInfo!(Name), funcInfo!(GenericArgumentList));
// Other exciting examples that make everyone think this is a good idea...
} This method has the following advantages:
I'm sure that there are other good reasons to implement a macro this way, I'm not familiar enough with rust to make the case for them. |
- `function` would be nicer but easily conflicts with existing code | ||
- `fn` would be consistent with how functions are declared | ||
- `function_path`, makes more sense if the `module_path` would be | ||
prepended (see below) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can func
also be considered as a name?
I'm guessing probably not because there's column
instead of col
(presumably there was a col!
before (but was renamed to column!
) since I see it mentioned here )
But I don't think fn!()
would be any good; wouldn't it conflict with fn
?
On the other hand, nothing seems to be using function
.
What about a compromise:
However, the function path (ie. those So, maybe it would be desirable to have a way to specify some arg(s) to help select which of those you want to have in the resulting output.
Eh, just a thought. Feel free to ignore :) |
This was previously discussed in rust-lang/rust#35651
Rendered