Skip to content

Comparable helper to compare by components#37894

Merged
ivanbasov merged 6 commits intodotnet:masterfrom
ivanbasov:comparable
Aug 28, 2019
Merged

Comparable helper to compare by components#37894
ivanbasov merged 6 commits intodotnet:masterfrom
ivanbasov:comparable

Conversation

@ivanbasov
Copy link
Contributor

A helper to compare objects by a series of components. If the first component are different, return the comparison. Otherwise, proceed with the second component and so on.

}

return this.CompletionItem.IsPreferredItem().CompareTo(other.CompletionItem.IsPreferredItem());
return IComparableHelper.CompareTo(
Copy link
Member

@genlu genlu Aug 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about the extra allocations here. Could this somehow end up in some hot path during completion and cause perf regression? #Resolved

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, agreed. i don't see how this wouldn't be a problem. #Resolved

{
internal static class IComparableHelper
{
public static int CompareTo<T>(T first, T second, params Func<T, IComparable>[] comparingComponents)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not certin we want this. will this be double allocation (the function, and the array?). Or do you intend to cache that all callside.

internal static class IComparableHelper
{
public static int CompareTo<T>(T first, T second, params Func<T, IComparable>[] comparingComponents)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why add to compiler layer? just have in IDE layer.

? f.CompletionItem.Rules.MatchPriority
: MatchPriority.Default,
f => f.CompletionItem.FilterText.GetCaseSensitivePrefixLength(f.FilterText),
f => f.CompletionItem.IsPreferredItem());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a cool concept. However, we should only do this allocation once.

@ivanbasov ivanbasov requested review from a team and removed request for a team August 16, 2019 23:38
@ivanbasov
Copy link
Contributor Author

ivanbasov commented Aug 16, 2019

Thank you, @genlu and @CyrusNajmabadi !
I have addressed the feedback. Please re-review. #Resolved

@ivanbasov
Copy link
Contributor Author

ivanbasov commented Aug 20, 2019

@genlu and @CyrusNajmabadi please review

#Resolved

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine :) Though i would prefer to see this used in more places to justify the code change. other examples might be: CodeFixService.GetFixesAsync, VirtualTreePoint.CompareTo, AddImport.Reference.CompareTo, CompletionHelper.CompareItems, MethodExtractor.Compare, WrapItemsAction.SortActions, MemberDeclarationsOrganizer.Comparer, ModifiersOranizer.Comparer, CompareNameParts, NameSyntaxComparer, TokenComparer.

If we can really show this being used in a lot of places, hte need for a helper becomes more apparent.

Comment
Submit general feedback without explicit approval.

@ivanbasov
Copy link
Contributor Author

ivanbasov commented Aug 21, 2019

@CyrusNajmabadi @genlu

I have applied the approach to multiple scenarios.
Here are scenario I could not apply it:

  • CompletionHelper.CompareItems
  • MemberDeclarationsOrganizer.Comparer
  • MemberDeclarationsOrganizer.VB
  • NameSyntaxComparer
  • NameSyntaxComparer.VB
  • TokenComparer
  • TokenComparer.VB

#Resolved

: MatchPriority.Default;

yield return completionItem.FilterText.GetCaseSensitivePrefixLength(filterResult.FilterText);
yield return completionItem.IsPreferredItem();
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely concerned. i think allocations in these paths are not ok. I think you should have to overloads. One that takes just an ImmutableArray<IComparable>s. Another that takes an ImmutableArray<IComparableWithState> and a state arg. That way this can be allocated once, and you can call the helper from here passing along filterResult as an arg that can feed through.

Does that make sense? #Resolved

Copy link
Contributor Author

@ivanbasov ivanbasov Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using immutable arrays, we exclude algorithms with variable length for comparison paths like https://github.com/dotnet/roslyn/pull/37894/files#diff-322fd889d857cd92d680c3f841a26094R43 #Resolved

Copy link
Contributor Author

@ivanbasov ivanbasov Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is IComparableWithState? #Resolved

Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

somehting you would have to define, but it would allow you to avoid captures by effectively stating that the delegate can be passed extra data. that way you can statically create the array of delegates, but pass data it needs dynamically. #Resolved

Copy link
Contributor Author

@ivanbasov ivanbasov Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @CyrusNajmabadi ! Hopefully implemented ComparerWithState.

@CyrusNajmabadi and @genlu please take a look. #Resolved

(p, b) => !b && !p.IsCaseSensitive,
// Consider a match to be better if it was successful without stripping punctuation
// versus a match that had to strip punctuation to succeed.
(p, b) => p._punctuationStripped);
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, i'm reviewing this but not actually confirming the lambdas match the original code. i hope you've done that. #Resolved

IReadOnlyList<string> names1, IReadOnlyList<string> names2,
bool placeSystemNamespaceFirst)
IReadOnlyList<string> names1, IReadOnlyList<string> names2,
bool placeSystemNamespaceFirst)
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo? #Resolved


namespace Roslyn.Utilities
{
internal delegate int ComparisonWithState<in T, in S>(T x, T y, S state);
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this type makes sense to me. #Resolved

/// </summary>
/// <typeparam name="T">Comparing type</typeparam>
/// <typeparam name="S">State</typeparam>
internal class ComparerWithState<T, S>
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not certain if these classes are needed? can't you make one bit ComparisonWithState out of N individual ones? #Resolved

=> new ComparerWithState<T>((t1, t2, state) => comparingMethod(t1).CompareTo(comparingMethod(t2)));
}

internal class ComparerWithState
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static class.

i can understand these helpers to build up a final comparer-thingy out of the individual pieces. I don't quite get the need the for the above classes. #Resolved

}
=> ComparerWithState.CompareTo(this, other, s_comparers);

private readonly static ImmutableArray<Func<FilterResult, IComparable>> s_comparers =
Copy link
Member

@genlu genlu Aug 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep the original comments? #Resolved

Copy link
Member

@genlu genlu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@ivanbasov ivanbasov merged commit 8d78f17 into dotnet:master Aug 28, 2019
@ivanbasov ivanbasov deleted the comparable branch August 28, 2019 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants