Rust doesn't have any explicit way to give closures a more recognizable name. Closures end up having non-descriptive names {{closure#0}} in paths and symbols, and noisy-looking types {closure@span}.
When I'm profiling code or checking cargo bloat output, having an anonymous …::{{closure}} symbol show up is annoying, because it can be difficult to figure out which closure is it.
JavaScript has a neat trick for this:
let frobnicate = () => {};
console.log(frobnicate.name);
> frobnicate
let tmp = frobnicate;
console.log(tmp);
> function frobnicate()
When closures are defined inside a let/var/const statement, they are named after the binding's name. rustc could do the same!
I like the idea, but this would unfortunately cause a lot of closure signature inference failures. An attribute on the closure would not have this problem (but would be a lot more syntactic noise).
Closure inference heavily relies on function parameter bounds, and thus things often break when you assign a closure to a variable and then pass it, instead of defining the closure in place. That limits the usefulness of the proposed feature.
It would be nice to fix that issue somehow (for many reasons beyond just this feature).
You could name the closure something that indicates "second closure in fn foo passed to a map() call" etc as well. Wouldn't just have to be assignment to variables that tried to give helpful names.
Or maybe take the first part of the body of the closure as part of the name? Or the line number?
I would personally like it if closures were named after the binding they belong to (like let x = || {}; being {{closure:x}}), and in free-standing closures that are passed as arguments then the natural name would be the name from the argument itself, but for Iterator::map the argument name is an uninspired f
(Assuming the names are coming from the trait declaration and not the effective implementation anyway. Not sure how I feel about the relative merits of that choice.)
There’s also the option of combining the function and argument name; imagine getting {{closure:map/f}}. That feels nice so you don’t have to pick names just for the occasional visibility of panic/debug output. Not sure how hard that would be to implement though.
While I was looking for something else, I noticed that -Zspan_free_formats=yes exists already, which renders like this:
error[E0308]: mismatched types
--> $DIR/issue-20862.rs:2:5
|
LL | fn foo(x: i32) {
| - help: a return type might be missing here: `-> _`
LL | |y| x + y
| ^^^^^^^^^ expected `()`, found closure
|
= note: expected unit type `()`
found closure `{closure@foo::{closure#0}}`
instead of
error[E0308]: mismatched types
--> $DIR/issue-20862.rs:2:5
|
LL | fn foo(x: i32) {
| - help: a return type might be missing here: `-> _`
LL | |y| x + y
| ^^^^^^^^^ expected `()`, found closure
|
= note: expected unit type `()`
found closure `{closure@$DIR/issue-20862.rs:2:5: 2:8}`
Making the output proposed in this thread for closures from the local crate would be quite easy. Funnily, for example wouldn't be able to use any of the proposals as the closure isn't bound to anything, other than the return value (so it could be something like {closure@foo::return}).
Seeing the changes in context, I think that instead of something like {closure@main::{_::filter#0}}, the output should be along the lines of main::{closure _::filter#0}.
Interesting, what is the effect on binary/debug info size? The new names are longer, but how often they are repeated / how common these sort of symbols are will determine if it a minor change or substantial.
I tend to agree. We don't specify the type description in every message like we do in the "expected/found" note, so you'll need a bit of redundancy anyways. I think something like
found closure `foo::{closure _::map#0}`
which composes somewhat fine when you have nested closures
found closure `foo::{closure x}::{closure _::map#1}::{closure y}`
even if it is a bit more verbose than
found closure `{closure@foo::{x}::{_::map#1}::{y}}`
No, that message (with the current formatting) has
found closure `{closure@foo::{closure#0}}`
------- --------- ------------
| || | |
| || | closing brace for closure path
| || closure name
| |prefix for a closure type
| opening brace for closure path
type description
I think that we can remove the prefix and maybe even the opening and closing braces (like, funnily enough, we already do for the symbol names).