Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If you're trying to achieve proper encapsulation, you just have a module that implements some sort of functionality, and shouldn't need to borrow anything from it. The real question is why you're pulling data instead of pushing messages.


This is incorrect. "Sending a message" involves borrowing the data so that the method can run. `foo.bar()` borrows `foo`.


Sorry, I wasn't clear. You are, of course, correct: you're only ever in a position to call a method if you hold a reference to the struct you're calling on.

My meaning was that you should favour a usage pattern that looks like you either move/copy things into the called method, or lend a reference to something you own (which is, presumably, not going to be held on to for very long), and then you're either given ownership of whatever return value you get, or get a reference whose lifetime depends on the arguments you passed in (but not the object itself). All of this ends up being quite clean, and you don't end up tying yourself into a borrowing knot.

You do end up in a weird place when your methods return references to fields of the owning object. When that happens, you're restricted in what you can do with the owning object until the reference goes out of scope. Rust mutexes are implemented precisely like that, which highlights what sort of behaviour you're getting from this usage pattern.

The former provides better encapsulation and more closely resembles the message-passing approach to OOP, whereas the latter pattern is not only not very ergonomic, it's quite indicative of poor encapsulation (because you're, by necessity, asking for internal state).


Here is the issue: `self.foo.bar(self.baz())` is an error if `foo.bar()` mutates foo, even if `baz()` doesn't touch `foo` and even if `baz()` doesn't return a reference. This is because borrowck doesn't properly understand that baz will be evaluated before bar, and can't distinguish which elements of a struct are accessed by that struct's methods. Both of these are problems that can be solved, and neither of them is actually promoting good practice in my opinion.

All it does is force you to use unnecessary temporaries, like `let baz = self.baz(); self.foo.bar(baz)`


Yeah, this is basically a borrowck "bug" which will probably be fixed post-MIR.

Note that there are cases where such code is invalid even with the temporary, and they can be related to Demeter. Ish. Also to API contracts; the guarantee should be embedded in the signature (so changing the internals shouldn't cause its usage to stop compiling), which is unweildy to do.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: