Renaming FnOnce to FnMove?


#1

I’ve always wondered this, but as this was a minor nit, I thought it was not worth discussing. But considering 1.0 as a final deadline for all the breaking changes, I finally took my courage to write this.

How about renaming FnOnce into FnMove?

Reading the IRC log happened a month ago, there was a similar suggestion:

<p1start> reem: But with the current system, Fn/FnMut matches with Deref/DerefMut
<p1start> And Index/IndexMut. Which is why I’d prefer FnMove to FnOnce: Deref/DerefMut/DerefMove : Index/IndexMut/IndexMove : Fn/FnMut/FnMove would be so neat

And I have the similar feelings. Every other aspect of the language consistently uses “”, “mut”, “move” to call three mechanisms that it uses, so being consistent with them would be good to see.

Possible downsides of this change are:

  • Personally, FnMove does not sound as attractive as FnOnce does. FnOnce emphasizes exactly what it does - it can only be called once!
  • It may confuse users who may think move || and FnMove are somewhat related. They are two different things, so labeling them with completely different names would be a better idea.

As I said earlier, this is just bikeshedding. Also, FnOnce and family are already marked as stable. But I do think that this would be the last chance to fix it, if I understand the problem correctly.

Thoughts?


#2

There’s actually basically a total lack of move in the libs/language today. Everything is into_ or from_. The only exception is the move keyword for a by-value capturing closure, which iirc was basically chosen as “the least awful” and didn’t actually have strong concensus/support.

FnOnce to me at least captures the very relevant detail of “this is a one-shot closure”, and the move stuff falls out of that. This is a bit related to how mut is a bit of a misnomer since it’s not really about mutability, but ownership. Cell and RefCell admit mutation of non-mut things.

edit: a quick search for move in the docs only turns up stuff in the compiler, largely because there hasn’t been a strong push to modernize conventions in there.


#3

A (very mild) counterargument: The move keyword governs the completely orthogonal issue of by-ref vs by-move capture, and we might confuse users further if we name one of the traits FnMove.

From FnOnce is at least clear that it can only be called once.

The three orthogonal dimensions of closures:

  • Capture mode: By-reference or by-move
  • Call mode: FnMut, Fn, FnOnce
  • Boxedness: <anonymous unique type> or trait object / trait pointer.

Rust gives you full control! With those degrees of freedom there is room for confusion.


#5

Of course, we could just do DerefOnce and IndexOnce, which may actually be better names.


#6

As far as I know, FnOnce doesn’t actually mean a move (and a moving is not always necessary). This is why there is the move keyword as well.


#7

As @carllerche said, whether or not a closure is marked move is orthgonal to whether it implements FnOnce, and I’d be reluctant to conflate the terms further.


#8

Reviving this thread because it’s still relevant. Although a breaking change couldn’t happen in Rust 1.0 anymore, this nevertheless seems to be something many people stumble upon. Maybe in scope for 2.0?

Having said that: this inconsistency in naming conventions also struck me as somewhat wrong. Rust usually emphasizes value types and pass-by-move by default, which is a great thing. So, shouldn’t pure undecorated Fn be the one that moves its environment, and the one that takes it by reference (currently, Fn) be called FnRef?

This would also avoid the conflation with the move keyword.


#9

From a usability standpoint, I myself would rather avoid any kind language update that requires major retraining for previously-existing things in the core language. Having something use a different name than it used to is confusing for language veterans, and has the cost of dropping productivity in many places in the ecosystem while those places switch Epochs.

Now if it’s a very useful change then I’m all for it, and I also understand the drive to get things “consistent”, but renaming something in a widely-used project (in this case the rust ecosystem as a whole!) just for the sake of it (or consistency) has IMO a much higher cost than any benefit such a change could provide: it requires retraining for pretty much any veteran, and would need at least a source translation tool to keep the work across the ecosystem that’s needed for this change manageable, but what you can do with the end result is not better in any way than the old version.

Thus, from a cost/benefit analysis POV my personal opinion is that established publicly exposed identifiers should generally just stay as they are.