Skip to content

Rust Error E0790: Cannot Call Associated Function on Trait

E0790 means you asked a trait for something that only a type can give you. Default::default() on its own is like saying “give me the default” without saying the default what. It’s a common error, and the fix is usually to put the type’s name in front: Settings::default() instead of Default::default(). This page shows the fixes first, then explains the difference between a trait and a type, so this error stops surprising you. It’s part of the compiler errors guide.

error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> src/main.rs:8:20
|
8 | let settings = Default::default(); // ❌ the default of which type?
| ^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use a fully-qualified path to a specific available implementation
|
8 | let settings = </* self type */ as Default>::default(); // ❌ the default of which type?
| +++++++++++++++++++ +

This is the program that produces it:

#[derive(Debug, Default)]
struct Settings {
volume: u8,
dark_mode: bool,
}
fn main() {
let settings = Default::default(); // ❌ the default of which type?
println!("{:?}", settings);
}

You get the same error when you call your own trait’s function on the trait name, like Shape::new(). Here rustc can see two types that implement Shape, so it lists both as options:

error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> src/main.rs:33:17
|
2 | fn new() -> Self;
| ----------------- `Shape::new` defined here
...
33 | let shape = Shape::new();
| ^^^^^^^^^^^^ cannot call associated function of trait
|
help: use a fully-qualified path to one of the available implementations
|
33 | let shape = <Circle as Shape>::new();
| ++++++++++ +
33 | let shape = <Square as Shape>::new();
| ++++++++++ +

For a trait constant like Plugin::ID, the headline changes slightly: cannot refer to the associated constant on trait without specifying the corresponding `impl` type. Same problem, same fixes.

Look at what rustc marks:

  1. ^^^^ under Default::default(): “cannot call associated function of trait”. default is a function that belongs to the Default trait, and you called it through the trait’s name.
  2. The help suggests </* self type */ as Default>::default(). The /* self type */ part is a blank for you to fill in. rustc is asking: “which type’s default do you mean?”
  3. In the Shape example, rustc fills the blank for you with each type it found (Circle, Square). If only one type implements the trait, it suggests just that one.

Here is the key idea. A trait is a promise: “any type that implements Default can make a starting value of itself”. A type is the thing that keeps the promise: Settings, String, u32 and Vec<T> each keep it in their own way. Default::default() asks the promise itself for a value, but a promise can’t make anything. Only a type can.

Think of a “takeaway available” sign. Many restaurants put it in their window. But you can’t order dinner from the sign; you have to pick a restaurant. Settings::default() is picking the restaurant.

Most trait methods take self, like circle.area(). Those never cause E0790, because the value tells Rust the type: circle is a Circle, so it calls Circle’s area. You can read more about this in Traits.

Some trait functions have no self: constructors like new() and default(), conversions like From::from, and trait constants like ID. With no value to look at, Rust has only two places to learn the type: the name you write in front (Settings::), or the type the result must have (let s: Settings = ...). If neither is there, Rust can’t guess. Many types implement Default, and picking one at random would quietly change what your program does.

This is the same as an interface in Java or C#. You can’t call new on an interface; you need a class that implements it. Rust just tells you about it at compile time, with the exact place to fix.

Choose this almost always. Replace the trait name with the type name. It’s the shortest fix, and it reads well: “the default Settings”, “a new Circle”:

#[derive(Debug, Default)]
struct Settings {
volume: u8,
dark_mode: bool,
}
trait Shape {
fn new() -> Self;
fn name() -> String;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
fn new() -> Self {
Circle { radius: 1.0 }
}
fn name() -> String {
String::from("circle")
}
}
fn main() {
let settings = Settings::default(); // instead of Default::default()
let shape = Circle::new(); // instead of Shape::new()
println!("{:?}", settings);
println!("A {} with radius {}", Circle::name(), shape.radius);
}

Output:

Settings { volume: 0, dark_mode: false }
A circle with radius 1
▶ Try it Yourself

Circle::new() works even though new is defined in the trait, not in an impl Circle block. Rust looks for new on Circle, finds it through impl Shape for Circle, and calls it. The trait must be in scope (defined in the same file, or brought in with use).

Choose this when you like the Default::default() style, or the type name is long. Write the type on the variable, and Rust works out which default to call from that:

#[derive(Debug, Default)]
struct Settings {
volume: u8,
dark_mode: bool,
}
fn main() {
let settings: Settings = Default::default();
let small: u8 = 42;
let big: u32 = From::from(small);
println!("{:?}", settings);
println!("{}", big);
}

Output:

Settings { volume: 0, dark_mode: false }
42
▶ Try it Yourself

This only works when the function returns the type itself (Self), as default(), new() and from() do. It does not work for fn name() -> String: knowing the answer is a String tells Rust nothing about which shape you mean. For those, use Fix 1 or Fix 3. More on annotations in Data types.

Fix 3: Fully qualified syntax <Type as Trait>::function()

Section titled “Fix 3: Fully qualified syntax <Type as Trait>::function()”

This is the “say everything” form that rustc suggests. Read <Circle as Shape>::new() as “the new that Circle has because it implements Shape”. It always works, but Circle::new() is easier to read, so you only need it when the short form is ambiguous:

  • the type implements two traits with a function of the same name, or
  • the type has its own function with that name, and you want the trait’s version.

Here a Sale can be written as a CSV row or as a printed report, and both traits have a header(). Writing Sale::header() gives E0034 “multiple applicable items in scope”, so you say which one:

trait Csv {
fn header() -> String;
}
trait Report {
fn header() -> String;
}
struct Sale;
impl Csv for Sale {
fn header() -> String { String::from("date,amount") }
}
impl Report for Sale {
fn header() -> String { String::from("Monthly sales") }
}
fn main() {
println!("{}", <Sale as Csv>::header());
println!("{}", <Sale as Report>::header());
}

Output:

date,amount
Monthly sales
▶ Try it Yourself

The Advanced traits lesson has another example, with methods that take &self too.

Fix 4: In generic code, use T:: and the turbofish

Section titled “Fix 4: In generic code, use T:: and the turbofish”

Choose this when you’re writing a generic function. Inside fn register<T: Plugin>(), the type is T, so call T::name() and T::ID, not Plugin::name(). When you call the function, pass the type with the turbofish ::<Type>, because there’s no argument for Rust to learn it from:

trait Plugin {
const ID: u32;
fn name() -> String;
}
struct Logger;
struct Backup;
impl Plugin for Logger {
const ID: u32 = 7;
fn name() -> String { String::from("logger") }
}
impl Plugin for Backup {
const ID: u32 = 12;
fn name() -> String { String::from("backup") }
}
fn register<T: Plugin>() -> String {
format!("Plugin #{}: {}", T::ID, T::name())
}
fn main() {
println!("{}", register::<Logger>());
println!("{}", register::<Backup>());
}

Output:

Plugin #7: logger
Plugin #12: backup
▶ Try it Yourself

If you leave out the turbofish and write register(), you get E0283: “cannot infer type of the type parameter T”. T is also the type here, so T:: works the same way as Circle:: in Fix 1. See Generics for more on type parameters.

Default::default() with nothing to go on. let config = Default::default(); fails, but the same call works wherever the type is already known: in a struct field, a function argument, or the “fill in the rest” syntax:

let settings = Settings { volume: 8, ..Default::default() }; // OK: Rust knows it's Settings

Fix the failing line with Settings::default() or let config: Settings = Default::default();. See Common traits.

Inside a generic function. Writing the trait name instead of T:

error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> src/main.rs:9:29
|
2 | fn name() -> String;
| -------------------- `Shape::name` defined here
...
9 | format!("This is a {}", Shape::name())
| ^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
9 | format!("This is a {}", <Circle as Shape>::name())
| ++++++++++ +

Careful: rustc suggests <Circle as Shape> because Circle is the only shape so far. That compiles, but the function would then always say “circle”, whatever T is. The right fix is T::name(), as in Fix 4.

Trait constants. println!("{}", Plugin::ID); asks the promise for a number, and only each plugin has one. Fix: Logger::ID, or T::ID in generic code.

From::from(x) with no target. let total = From::from(42u8); gives E0790, because many types can be made from a u8. Fix: u32::from(42u8), or let total: u32 = 42u8.into();. See Conversions.

  • E0282: type annotations needed. If you use the value later, like let c = Shape::new(); followed by c.area(), rustc reports E0282 instead. The same fixes work.
  • E0283: type annotations needed when many types fit, for example Into::into(n) with no target, or a generic function called without the turbofish.
  • E0599: no function found. Settings::default() gives this if Settings doesn’t implement Default; add #[derive(Default)]. With let s: Settings = Default::default(); the same mistake shows up as E0277.
  • E0424: self used in a function without a self parameter. Also about functions that belong to a type rather than to one value.
  • All compiler errors: the full list of error pages.

Quick check

1. let opts = Default::default(); gives E0790. Options derives Default. Which line fixes it?

2. Why does let s: Settings = Default::default(); compile, but let n: String = Shape::name(); still gives E0790?

3. Inside fn show<T: Shape>(), how should you call the trait function name()?

Score: 0 / 3