Why do so many examples use 'extern crate'?

Just for completeness: while it is true that extern crate "statements" are not needed in edition 2018 anymore (except for test, or, for older compiler version, proc_macro), the #[macro_use] extern crate ... idiom can still be useful (in that it cannot be replicated by use "statements"). Indeed, once you #[macro_use] extern crate some_crate, all the macros exported by ::some_crate are in scope even inside (sub)modules:

//! Entrypoint: `lib.rs` or `main.rs`

#[macro_use]
extern crate log;

mod something {
    // `debug!` can be used here
}

vs.

mod something {
    // `::log::debug!` (or `log::debug!` if no (other) `log` item in scope) can be used here
}
// or
mod alternative {
    use ::log::debug; // or `log::debug` if no (other) `log` item in scope

    // `debug!` can be used here.
}

Basically, with use "statements", macros behave like any other item (function, type) regarding namespaces and scopes, but it can sometimes be convenient to be able to add something to this "global / ubiquitous scope" (called the prelude). And the only way to do so currently is by using #[macro_use] extern crate ....

Ideally, there should be an actual mechanism to customize one's prelude, and once that's available, #[macro_use] extern crate could definitely be deprecated.


Also, see this other post where I detail how one can "hand-roll a custom prelude": What's the difference between 'extern crate' and write into cargo.toml - #20 by Yandros

2 Likes