ignore: fix confusing lifetimes in ParallelVisitor{,Builder} with an associated type #3012
+217
−78
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
The docs for
WalkParallel::visit()
state the following:However, by accepting an
&mut dyn ParallelVisitorBuilder<'_>
, thevisit()
method makes it rather unclear when the builder'sDrop
method is called. There's also no example of this custom visitor usage in the repo, and all examples instead use the neighboring.run()
method.It's also relatively unclear what the purpose of the lifetime
's
inParallelVisitorBuilder<'s>
is--I understand it's supposed to just avoid the need to enforce a'static
lifetime so we can usestd::thread::scope()
, but implementors may not know what to do with it. While looking to use this API, I was under the impression that the builder would be able to create visitors scoped to the builder's lifetime, but this ended up not being possible, because of the&mut self
requirement meaning that the builder can't hand out references to its own fields. This further increases confusion about where and how theDrop
impl of the builder is supposed to get called.Finally, the API requires creating a
Box
where none is necessary. This is very unlikely to cause any performance issues, but is a little awkward.Solution
ParallelVisitorBuilder
return a lifetime-annotated associated typeSelf::Visitor<'s>
.build()
method return a concrete instance ofSelf::Visitor
, scoped to the builder's own lifetime.WalkParallel::visit()
method accept animpl ParallelVisitorBuilder
, which allows the user to move a builder into thevisit()
method so that theDrop
method can be called immediately after the conclusion of the parallel traversal.WalkParallel::visit()
method return theParallelVisitorBuilder
argument after completion.Result
The
.run()
and.visit()
methods' signatures were modified, but this should make them strictly more general. I've removed a fewBox::new()
calls to demonstrate how this works, but the code will still compile with theBox::new()
calls. The newly added example script looks like:Because of the more expansive API which allows the builder to be consumed by the
visit()
call, it is now clear from a glance that the result of the successful first crawl will be printed to stdout, before the failing second crawl is started at all. It is also clear that if the failing second crawl is removed, there will be no deadlock, because we were able to have the builder take ownership of its data and return a result on the stack instead of creating extraneousArc
andmpsc::channel
instances.It is my belief that this approach is much easier to follow, and actually fulfills the expectations of the existing docstring for
WalkParallel::visit()
.