Consider formatting Iterator specially in `?eval`?
The situation often comes up that you want to demonstrate some iterator chain using ?eval. Directly writing the iterator yields bad results:

The obvious workaround is to collect into a vector:

However, this workaround is slightly problematic:
- it adds boilerplate
- it may confuse beginners, particularly with the heavy syntax (
::<Vec<_>>) - it encourages beginners to overuse vector allocations instead of iterating iterators directly
Perhaps there is a way to special-case the return value formatting for iterators? In the above example, the bot output could look like this:
1, 3, 5, 7, 9
Advantages:
- Code is simple to write, easy to read, pretty
- Output is very pleasant to look at
- No boilerplate for users
- Doesn't lead beginners to over use vector allocations
Potential difficulties:
- Tricky to implement. Requires either a hackish display trait with a specialization for iterators; OR static analysis to determine te type of the return value. Both are not great
- Introduces more "magic" to the bot. It may be hard to understand for bot users where this formatting is coming from
- What to do on long or endless iterators? (Probably best to just render an ellipsis after a certain number of items)
In hindsight, I'm thinking this is way too much effort and too brittle for little benefit.
Dtolnay had discovered a clever trick to emulate specialization using autoref. This trick can be applied here to provide a specialization output format for Iterators.
The final generated code looks like this:
struct Wrap<T>(T);
trait Output {
fn output(self);
}
impl<T: Iterator> Output for Wrap<T> where T::Item: std::fmt::Debug {
fn output(mut self) {
if let Some(item) = self.0.next() {
print!("{:?}", item);
for item in self.0 {
print!(", {:?}", item);
}
println!();
}
}
}
impl<T: std::fmt::Debug> Output for &Wrap<T> {
fn output(self) {
println!("{:?}", &self.0);
}
}
fn main() { Wrap({
// USER CODE HERE
}).output(); }
This code can presumably be minified considerably. The utility structs and traits might also have to be wrapped in a macro for hygiene, so that the user doesn't accidentally use Output or Wrap in their own code and is confused about the result.
Now, I tested this code with a few types and it yielded the correct results each time. It seems robust enough, so the "tricky to implement" concern from above is dealt with I think.
The "magic" concern is definitely still valid though, in two aspects:
- it may be hard to understand for bot users where the special iterator formatting is coming from
- users may be confused when the bot redirects them to the playground and they're greeted with a wall of funky glue code
- this aspect could be alleviated by falling back to the simple old formatting mechanism only when sharing the playground to the user. However, this is another hack on top of a hack. Objectively speaking, it seems viable, though it kinda feels wrong
Remaining questions:
- is the bot complexity worth it for the convenience?
- should the bot sneakily remove the complex iterator formatting mechanisms when sharing the generated code to the user?
- what to do on long or cyclic iterators? Print
...after a certain number of items or a certain number of printed characters?