New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Combine overload for IncrementalValuesProvider<T> #58127
Comments
I don't like the name |
Would |
Potentially yes. Note that Razor identified a use for true |
We deliberately left out the IncrementalValuesProvider<INamedTypeSymbol> symbols = context.SyntaxProvider.CreateSyntaxProvider(...);
IncrementalValuesProvider<string> left = symbols.Select(static (item, token) => GatherInfoA(item));
IncrementalValuesProvider<string> right = symbols.Select(static (item, token) => GatherInfoB(item));
var crossJoin = left.Combine(right.Collect()).SelectMany(static (pair, _) => pair.right.Select(static rightItem => (pair.left, rightItem)); This isn't particularly inefficient. The gather's are called only as needed, and the collect() will be considered cached if all items in it are. When the right hand side changes, the select many will always be called, but the resulting tuples will essentially be 'cached out' in that most of them produced won't be modified so no downstream nodes will be executed for them. Given that the SelectMany is cheap (comparatively) to run, you shouldn't see any perf downsides to doing it this way. |
Wait, I'm confused. While the name would be the same, this doesn't seem to be the semantics I'm proposing in this issue. I don't want a cross-join (MxN items), I want a zip of two sequences of equal length. I do agree with @sharwell that maybe a different name (eg. |
Background and Motivation
I find myself often ending up in a situation where I'd like to combine two
IncrementalValuesProvider<T>
instances, essentially "zipping" them. There doesn't seem to be an API for doing this though, as the existingCombine
methods only accept one of the left/right values being anIncrementalValueProvider<T>
instance. Consider the following simplified scenario:The rationale here is that:
left
is used on its own in a first source production noderight
GatherInfoA()
again for each item inright
, as I already have that infoGatherInfo_()
might be expensive, so I really just want to reuse the result I haveProposed API
namespace Microsoft.CodeAnalysis { public static class IncrementalValueProviderExtensions { + public static IncrementalValuesProvider<(TLeft Left, TRight Right)> Combine<TLeft, TRight>(this IncrementalValuesProvider<TLeft> provider1, IncrementalValuesProvider<TRight> provider2); } }
Alternative solutions
Consider this scenario:
One possible workaround doable today is to do something like this:
Which does yield back an
IncrementalValuesProvider<(A, B)>
sequence, but this doesn't seem efficient at all. The fact I'm doingCollect()
on both means that every time a single item in the sequences is removed/added/updated, the entire collection will be reevaluated, instead of just that one item. What I'd like instead is to just have individual items that are changed to be queried for reevaluation, with the guarantee that if both source sequences have no incompatible filters on them (that is, either they have noWhere
calls, or if they do, they have one that applies the same filtering on both sequences), then I'll just get asked to recompute a single pair of items in this resulting values provider combining the two.Notes
In order for this to work, Roslyn needs to guarantee that items in the same position across different
IncrementalValuesProvider<T>
instance will match and refer to the same source item. As in, this will only work if Roslyn can guarantee that transformations on the values providers are "stable": the two input sources will always have the same number of items when processed (if the user hasn't messed up filtering) and that items will not be reordered in just one of the two providers. That is, if source itemA
is used to produceB
andC
in the transformed producersleft
andright
, then callingCombine
on them should guarantee that each resulting pair will correctly associate itemsB
andC
for each original source itemA
used to produce them.cc. @sharwell and @jkoritzinsky who will involved in this conversation on Discord 🙂
The text was updated successfully, but these errors were encountered: