What's happening here?

I've saw something like

fn something<T: SomeTrait>(thingy: T) {
    T::some_method()
}

or

fn something<T: SomeTrait>(thingy: T) {
    T.some_method()
}

the other day and I have no idea what this is doing, but I'm pretty sure it compiled.

I attemped to google "rust call method on type parameter" and "rust call method on trait bound" but got nothing back, and crapgpt was no help either. I've been doing rust for quite a bit and have never seen this before, so I feel it must be some kind of obscure syntax thing.

Please enlighten me as to what on earth is going on here.

The ::some_method() thing is called fully-qualified syntax, and you can read more about it here.

You might have meant thingy.some_method. This is how traits work. You can read about traits here.

1 Like

You might have seen something like this, demonstrating use of fully qualified syntax:

struct SomeStruct {}

trait SomeTrait {
    fn some_method(&self);
}

impl SomeTrait for SomeStruct {
    fn some_method(&self) {}
}

fn something<T: SomeTrait>(thingy: T) {
    // Call method the usual way on this instance of thingy
    thingy.some_method();

    // Call method via it's fully qualified name passing this thingy as the self parameter
    T::some_method(&thingy);
}

3 Likes

T::some_method() can also be what Rust calls an associated function and many other languages call static methods or class methods – ie. just a normal function with a fancy name. For example, Vec::new() (though that one is of course not a trait function but an inherent one).

3 Likes

Yes. Like so:

struct SomeStruct {}

trait SomeTrait {
    // Associated function (sstatic method). No self parameter
    fn some_func();
}

impl SomeTrait for SomeStruct {
    fn some_func() {}
}

fn something<T: SomeTrait>(thingy: T) {
    // Cannot do this because some_func has no self parameter
    //thingy.some_func();

    // Call associated function via it's fully qualified name
    T::some_func();
}
2 Likes

Not really. He was talking about associated functions (methods that don't have a self parameter).

Yes really. In my new example the associated function does not have a self parameter. As you say.

Not really. You might want to read the documentation for Associated Items - The Rust Reference.

I found the code snippet that was doing my head in, and it's this from this page on the serde book:

pub fn from_str<'a, T>(s: &'a str) -> Result<T>
where
    T: Deserialize<'a>,
{
    let mut deserializer = Deserializer::from_str(s);
    let t = T::deserialize(&mut deserializer)?;
    if deserializer.input.is_empty() {
        Ok(t)
    } else {
        Err(Error::TrailingCharacters)
    }
}

I was a bit confused about it being fully qualified synatax, it made sense at first and I was just "Ohh that's just another form of fully qualified" but I just read up on fully qualified and it seems you'd need to do <T as SomeTrait>::some_func() for it to be that, but reading the later reply and the docs for Deserialize::deserialize where there's no self parameter it seems as if it could be calling a static function as where ZiCog said it's a "associated function". So I guess that's something.

I don't understand what you are trying to say. The doc at the link you gave says:

Associated functions are functions associated with a type.

How is some_funcin my example not that?

1 Like

Traits are not types in Rust.

What I'm trying to say is that jdahlstrom implicitly excluded associated methods declared in traits when he said:

Since we were initially talking about traits only. Thus cornering his comment to just associated functions for types.

It's a page about type parameter defaults, so the meat related to this topic is spread out, but I talk about various path-related expressions on this page.

trait Trait<One, Two = String>: Sized { ... }

// These act the same
let _: (i32, (), _) = Trait::foo(0);
let _: (i32, (), _) = Trait::<_, _>::foo(0);
let _: (i32, (), _) = <_ as Trait<_, _>>::foo(0);

// These act the same
let _: (i32, (), _) = Trait::<_>::foo(0);
let _: (i32, (), _) = <_ as Trait<_>>::foo(0);
struct HashSet<Key, S = RandomState> { .. }

// These act the same (and would search for inherent functions)
let mut hs = HashSet::default();
let mut hs = HashSet::<>::default();
let mut hs = HashSet::<_, _>::default();
let mut hs = <HashSet::<_, _>>::default();
// Mostly the same but only looks at the `Default` trait
let mut hs = <HashSet::<_, _> as Default>::default();

// These act the same (and would search for inherent functions)
let mut hs = HashSet::<_>::default();
let mut hs = <HashSet<_>>::default();
// Mostly the same but only looks at the `Default` trait
let mut hs = <HashSet<_> as Default>::default();

You have successfully confused me :slight_smile:

I still think my examples stand as a valid examples for the syntax in question.

Sure, I agree. My comment was just a nitpick :slight_smile: .

In the example in question T::some_func(); is not a call to a function of the type T, but of the (only) trait SomeTrait which T implements. That's how generics work.
The compiler cannot make any assumptions about T's methods if it is not bound by trait bounds.
And it can only resolve this to a specific trait's method if it isn't ambiguous:

Otherwise you'd need to call SomeTrait::some_func() explicitly, or, more explicitly <T as SomeTrait>::some_func().

So T::some_method() can never be a call to an associated function if T is a generic type parameter, only if T is a concrete type, like struct T { ... }.

Also associated functions and class methods (or static methods) are unrelated principles.
You can have associated functions, which take self or don't and you can have trait methods, which take self or don't.

I think I'm confused by naming/terminology. If T::some_method() in the OP's example is not a call to an associated function then what is the thing it is calling actually called?

A trait method.

Yes... and no. As jdalhstrom wrote:

And from the documentation:

Associated functions whose first parameter is named self are called methods and may be invoked using the method call operator, for example, x.foo() , as well as the usual function call notation.

Afaik, for the lack of a better term in Rust we call associated functions without a self parameter simply associated functions, to differentiate them from methods. Thus being what are called static methods in other PLs.

1 Like

But, but, it has no self parameter. I would have thought that made it not a method. After all it has no instance it can be a method of.