Cannot find function

The syntax is different for calling an associated function and calling a free function. I don't personally think that it is unreasonable.

OK, I understand, but then, if I don't keep it in the impl block it somewhat looses the "belongs to" property and becomes a "free" function, which I wouldn't like to do.
I simply don't understand why the compiler complains about it.

In Rust, you always have to use self when accessing something on self. The language is just being consistent. It's the same for methods and fields.

Yes, I suppose so. TBH, seeing self everywhere in the code, drives me nuts.

I tend to prefer free functions, but didn't always. Coming to Rust after doing a lot of OO development, at first I too wanted my functions to 'belong' to a struct.

Realizing two things helped me change:

  1. Rust's level of encapsulation is not the struct or impl block, but the module. Free functions have total access to the struct's private fields and functions, and they do not have to be public at all. They can even be located in a sub-module and still have total access. This means encapsulation is a complete non-reason for choosing associated functions over free functions. Instead, reorganizing your modules to map closer to what you would consider an OO 'class' in other languages leads to better organized code in my opinion.

  2. If a function doesn't operate on a specific instance of a struct, then making it an associated function doesn't buy you much even in terms of syntactic sugar, and can actually hurt chances for reuse. This can prevent you from seeing the function might be useful outside the context you originally envisioned for it.

I tend to limit associated functions to only methods that take some form of self parameter, and constructors.

4 Likes

Then the impl block seems bit pointless tbh.
Also, thanks for making me aware that free functions do have an access to struct's private fields. I was totally unaware of that.

You still need impl blocks to declare methods and associated constants.

struct Foo {
    x: String,
}

impl Foo {
    pub const BAR: usize = 42;
    
    fn len(&self) -> usize { self.x.len() }
}

Surely:

fn len(f:&Foo) -> usize { f.x.len() }

would do the same?

The function you defined there would be called with len(&foo), not foo.len().

Functionally yes, but you would lose a lot of the benefits that method syntax gives you like method chaining and using the "object" mindset instead of a more procedural one.

Yes, I'm aware of that. I'm simply questioning point of having impl block where in fact everything can be done without it, or, its usage is of very, very limited point. (After what I've learned about free functions)

You wouldn't loose method chaining if you return &mut to that object.

If len is not a method, you can no longer write an expression like this as a method chain:

x.bar().foo().len()

Instead, you would need to write:

len(&x.bar().foo())

Tbh, the second form is more readable.

FYI https://github.com/rust-lang/rust/pull/78420

4 Likes

Does it mean that next version of Rust will have more descriptive compiler error?

Yes.

Thanks man!

1 Like

I also observed that in the PR you are talking strictly about traits. I hope the compiler will provide correct description for impl blocks as well?

We already gave the appropriate suggestion inside impl blocks and the new label is "agnostic" to its scope.

1 Like