Fair enough. Imho unwinding and drop glue are also examples of modified evaluation order. They contain some control flow which isn't directly visible in code. They execute after the defining expression rather than before, but is it that much of a difference?
Have you seen the example for this pattern in real-world code with real-world names that I linked in a recent thread? Imho it looks much less appealing in real life, where variable names are long and there are many captures. Worse, you need your capture declaration in sync with the usage in closure body, which looks quite annoying.
I vaguely recall you disliking mut
annotations on bindings because the benefit is supposedly small while keeping them in sync with changing downstream usage is annoying. Do I remember correctly, or what it someone else? Explicit captures look like a similar issue, but with even fewer benefits. At least a lack of mut
tells me something about the changes to the value of a variable. Explicit captures don't serve any other need than making the compiler accept our code. If we could magically keep references to the stack of the returning function (e.g. by using a global GC), we wouldn't need those annotations.
I also think that preceding capture annotations are harder to keep in sync with the closure's body than local .move
s. The annotation itself doesn't tell you anything about the ways the binding is actually used, and getting it from the body of a potentially large closure can be difficult. On the other hand, if I see foo(bar.clone().move)
, then I immediately know that this is the only place where the value of bar
is cloned and used (or at least any other place can be considered independently, and likely uses bar
in a different way). If subsequent code changes in a way which makes the clone above the last usage, I can just remove the clone call and leave bar.move
. It's an easy change with easy consequences. If I had a clone bar
capture annotation, first I'd have to check that bar is really used only once in the body (ok, this can be a lint). Then I do what? Remove clone
and be left with bar
? Specify move bar
? Remove explicit annotation and use autocapture? If we use syntax like proposed by @newpavlov in that thread, with different groups for different types of captures, I also need to move bar
from clone
group to the move
group. That's relatively a lot of work, and a single change to code may make you redo it.