Writeln!() macro missing important import


#1

When I try to use the writeln!() on a file, it looks like the macro forgot to include the appropriate import?

   Compiling hello v0.0.1 (/src)
error[E0599]: no method named `write_fmt` found for type `std::fs::File` in the current scope
 --> hello.rs:8:5
  |
8 |     writeln!(file, "Hello World!");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: items from traits can only be used if the trait is in scope
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
help: the following trait is implemented but not in scope, perhaps add a `use` for it:
  |
3 | use std::io::Write;
  |

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: Could not compile `hello`.

Could we add use std::io::Write; inside the macro?


#2

Unfortunately, no.

writeln! is specifically designed to work not only with types that implement std::io::Write, but also types that implement std::fmt::Write. Both traits define a write_fmt method with essentially the same signature (the error type is different, but this is immaterial to the macro). That way, writeln! is “duck typed” so that it can be used with types implementing either trait.

I’ve always been suspicious of this design, and the fact that the macro throws this error (which can be especially confusing to new users) instead of just working out of the box is one of the negative attributes of it. But that’s how it works.


#3

What would prevent the macro from bringing both into scope though?

Edit: Oh, I guess it’s because std::writeln! is really just core::writeln!, and std::io::Write is only in std, so that could get tricky…


#4

Also, if you bring both into scope it would no longer be clear which of the 2 methods should be called