-6

Consider this code:

use chrono::{Local, NaiveDate};

fn main() {
    let d = Local::now().naive_local().date();
    println!("{}", d.num_days_from_ce());
}

This fails to compile with the strange error, "no method named num_days_from_ce found for struct NaiveDate in the current scope".

What? No method name? It's right there in the documentation‽

It took me a while to figure out I needed to add Datelike to the things I'm using from chrono. So my question is, why? Why force the consumers to have to import dependencies manually that we aren't using directly? This is not the only case of these necessary phantom imports in Rust...

Maybe there is something about Rust that I am not understanding here, or maybe there is something that can be changed about this library so that consumers don't need to use DateLike in this situation.

Also, why can't the compiler recommend WHAT to bring into the current scope?

Another issue with this syntax is that it produces a compiler warning that these necessary phantom imports are unused. Thus, there is no possible way for my code to compile cleanly...

warning: unused imports: `Datelike`, `NaiveDate`, `Weekday`
  --> src/bin/foo/bar.rs:25:18
   |
25 |     use chrono::{Datelike, Duration, Local, NaiveDate, Weekday};
   |                  ^^^^^^^^                   ^^^^^^^^^  ^^^^^^^
Jim
  • 3,821
  • 1
  • 28
  • 60
  • 5
    You should always look at the full error message, it explains clearly what the error is: "help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope; perhaps add a `use` for it: `use chrono::Datelike;`" why it is that way is explained here: [Why do I need to import a trait to use the methods it defines for a type?](https://stackoverflow.com/questions/25273816/why-do-i-need-to-import-a-trait-to-use-the-methods-it-defines-for-a-type) – cafce25 Mar 30 '23 at 19:20

1 Answers1

2

Rust has a rule that you cannot use trait methods unless the trait is in scope. If the trait is not in scope, you can still use the functions, just not with the postfix method syntax.

use chrono::Local;

fn main() {
    let d = Local::now().naive_local().date();
    println!("{}", chrono::Datelike::num_days_from_ce(&d));
}

But for nearly all cases, you'll bring the trait in scope and use the method syntax. Many of the standard library traits, such as Iterator, are imported automatically.

This rule exists for API reasons. Anyone can implement a trait on a foreign type, so if two of your dependencies each have a trait with a method with the same name, it creates an ambiguity. Dependencies don't have an ordering, so picking one over the other would be ambiguous. If this caused an error, it would mean a crate implementing a trait could be a breaking API change. Instead, rust requires the trait to be in scope, which avoids these problems.

This also allows easily calling trait methods when the actual type has a method of the same name. For example, if a type has a method called borrow and also implements the Borrow trait, doing value.borrow() will call the type's method, but when Borrow is in scope, it will call Borrow::borrow.

drewtato
  • 6,783
  • 1
  • 12
  • 17
  • 1
    Please avoid putting answers on questions that already have been asked elsewhere, that way we can consolidate them in a single place and have more eyes on them at the same time, if you feel you have to add something to the already existing answers post your answer on the linked question instead. – cafce25 Mar 30 '23 at 19:42
  • thanks @drewtato, but this doesn't answer my core question of why can't the compiler recommend what to bring into scope? – Jim Mar 30 '23 at 20:32
  • 1
    @Jim it does. Read the error message. – drewtato Mar 30 '23 at 20:35
  • There is mention of `DateLike` in the error message. That's exactly my point. Also, what about the compiler warnings issue? – Jim Mar 30 '23 at 20:41
  • rust-analyzer can auto import the trait if your editor supports it, and the warning is unrelated to the original question. [You should consider opening a new question instead of editing this one.](https://meta.stackexchange.com/q/43478/1316885) – drewtato Mar 30 '23 at 20:52
  • The entire point is this question is to ask how to use this imports so that it compiles WITHOUT getting a clippy error that the import is unused... you still have not answered that. – Jim Apr 15 '23 at 03:45