5

I am learning Rust coming from a Java background. In Java, I would commonly import java.util.ArrayList;. As far as I understand, this was a convenience to prevent needing to put java.util. preceding every occurrence of ArrayList.

Consider the following Rust:

use std::io;
use std::io::Write;

fn main() {
    print!("Hello World!");
    // Let's flush the Buffer
    io::stdout().flush().expect("Oh No!");
}

If the first use is removed, io is no longer specified. We can fix this by adding std:: before io.

The program now reads like this:

use std::io::Write;

fn main() {
    print!("Hello World!");
    // Let's flush the Buffer
    std::io::stdout().flush().expect("Oh No!");
}

What catches my interest is the second use - It is required to use the flush method on stdout. This makes my Java analogy very unhappy - I expect flush to be a part of the "stdout thing", and if I have the thing I can use the methods - but that is clearly not the case here.

Is it possible to write the above program without the second use? If so, what is the syntax to fully specify flush?

What is going on?


Solution

Solved by some helpful comments below. The linked questions, while not the same question, do have similar answers.

The line in question:

std::io::stdout().flush().expect("Oh no!");

In my experience, stdout.flush() implies that flush is a function within stdout. In Java, stdout would be an object, passed to flush "behind-the-scenes" as this. In Python, it would be explicitly in the method signature as self.

In Rust, in this situation, stdout is being passed to flush via dot notation. To fully specify flush, stdout must be passed in the "traditional" way, within flush's parenthesis.

In short, Object.method() is equivalent to method(Object). (At least here - I am still learning, and may be very wrong.)

To fully specify both stdout and flush, I use the following:

std::io::Write::flush(&mut std::io::stdout()).expect("Oh no!");

Looking further, the first argument to expect is "self", furthering the x.y() == y(x) idea. Translating the above into y(x) format completely, we arrive at the very complicated:

std::result::Result::expect(
    std::io::Write::flush(
        &mut std::io::stdout()
    ),
    "Oh no!"
);

This has been enlightening. Thank you all, and I hope this helps someone in the future.

Navigatron
  • 416
  • 1
  • 4
  • 12
  • 1
    In your case, the duplicate suggests `std::io::Write::flush(&mut std::io::stdout())`. The fully qualified syntax (where you specify both the trait and the type) would look similar to `::flush(&mut std::io::stdout)`. – trent Jan 08 '19 at 03:11
  • You may also find [What is a concise way to inform the compiler of the specifc type with multiple implementations of a generic trait?](https://stackoverflow.com/q/48263001/3650362) interesting. – trent Jan 08 '19 at 03:14
  • @trentcl, that is exactly what I was looking for. Thank you! – Navigatron Jan 08 '19 at 03:20

0 Answers0