How do you navigate Rust code to find the necessary imports?

This code from the docs shows how to generate a random number.

let mut rng: ThreadRng = rand::thread_rng();
let y: f64 = rng.gen();

The gen() method is missing and requires importing.

In my IDE I just press a key to import missing symbols, and this appears at the top of the file.

use rand::Rng;

But I am confused about how this trait was chosen. The ThreadRng struct looks like this, and there's an another block implementing the RngCore trait.

pub struct ThreadRng {
    // Rc is explicitly !Send and !Sync
    rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
}

impl RngCore for ThreadRng {
    ...
}

But Rng is nowhere to be seen (I know where it is, but I wouldn't have found it without IDE autoimports).

If this were a Java program, for example, ThreadRng or something inheriting it would contain the method gen() if it implemented the Rng interface.

My question is how to navigate Rust code to find the right things to import? Is there something analogous to looking for implementations of an interface in Java?

Yes, it's the "Implementors" section of a trait, though it does not show every type implementing that trait (types from 3rd party crates that implement that trait are not part of that list). With Rng it is a little bit more complicated, as it has a supertrait (RngCore) and is implemented for every type that implements RngCore. These kind of traits are called extension traits (I think), exposing extra functionality based on a supertrait, without any need for implementing it. This is similar to Stream and StreamExt, for example. You implement the former and get the latter for free.

4 Likes

Two steps to find .gen on ThreadRng:

  1. impl RngCore for ThreadRng: a basic trait impl
  2. impl<R: RngCore + ?Sized> Rng for R: an indirect blanket impl

So usually you'll get the right imports from its documentation.
But rand crate only shows a basic example by importing a prelude mod (use rand::prelude::*;).
And also unfortunately rustdoc doesn't show the indirect blanket impl on ThreadRng and there is no indicator on RngCore rustdoc page except an unconspicuous sentence

End users should normally use the Rng trait from the rand crate, which is automatically implemented for every type implementing RngCore.

So you still rely on a friendly documentation to know which trait you should use.

4 Likes

Or you know that such a thing as a "blanket impl" exists, and you start looking for one.

1 Like

By the way, the compiler can often give you the same information.

I start with

fn main() {
    let mut rng: ThreadRng = rand::thread_rng();
    let y: f64 = rng.gen();
}

Rust Playground

and get

error[E0412]: cannot find type `ThreadRng` in this scope
 --> src/main.rs:2:18
  |
2 |     let mut rng: ThreadRng = rand::thread_rng();
  |                  ^^^^^^^^^ not found in this scope
  |
help: consider importing this struct
  |
1 + use rand::rngs::ThreadRng;
  |

I add the import

use rand::rngs::ThreadRng;
fn main() {
    let mut rng: ThreadRng = rand::thread_rng();
    let y: f64 = rng.gen();
}

Rust Playground

and get

error[E0599]: no method named `gen` found for struct `ThreadRng` in the current scope
  --> src/main.rs:4:22
   |
4  |     let y: f64 = rng.gen();
   |                      ^^^ method not found in `ThreadRng`
   |
  ::: /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/src/rng.rs:93:8
   |
93 |     fn gen<T>(&mut self) -> T
   |        --- the method is available for `ThreadRng` here
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
1  + use rand::Rng;
   |

I add the other import (by the way in the playground, you can even click on those suggestions to apply them) and it works:

use rand::Rng;
use rand::rngs::ThreadRng;
fn main() {
    let mut rng: ThreadRng = rand::thread_rng();
    let y: f64 = rng.gen();
}

Rust Playground

5 Likes

One of the issues is that the latest rand release is older than some relevant improvements to rustdoc. If you look at the docs locally

cargo new my_test_crate
cd my_test_crate
cargo add rand
cargo doc --open

you’ll discover that the blanket impl for Rand does appear on the documentation page of ThreadRng.


In any case, in the context of the rand crate, searching for gen is also useful enough:

6 Likes

Great!

Huh, might be a good idea to rebuild the docs for the latest version of all crates that were built with an old version? Once a year or so. Can't do it too often, and need to spread out the load over time obviously.

I occasionally come across crates that have way different formatting (no dark theme for a start). I assume they are also affected by this? (But maybe that is good as a warning to the reader that something is outdated?)