Skip to content
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

Expose SeparatedSyntaxList<T>.GetWithSeparators() through interface #73575

Open
Rekkonnect opened this issue May 19, 2024 · 9 comments
Open

Expose SeparatedSyntaxList<T>.GetWithSeparators() through interface #73575

Rekkonnect opened this issue May 19, 2024 · 9 comments
Assignees
Labels
Area-Compilers Concept-API This issue involves adding, removing, clarification, or modification of an API. Feature Request
Milestone

Comments

@Rekkonnect
Copy link
Contributor

Background and Motivation

SeparatedSyntaxList<T> is a generic type, so when a value of this type is retrieved via reflection, we don't have a useful non-generic type to refer to. GetWithSeparators() returns SyntaxNodeOrTokenList which is unbound to the generic type, thus requiring unnecessary workarounds, like this:

// given:
IReadOnlyList<SyntaxNode> list;
var listType = list.GetType();

var genericDefinition = listType.GetGenericTypeDefinition();
if (genericDefinition == typeof(SeparatedSyntaxList<>))
{
    // we use the underlying node or token list to display children
    SyntaxNodeOrTokenList nodeOrTokenList = (list as dynamic).GetWithSeparators();
    return Use(nodeOrTokenList);
}

Proposed API

 namespace Microsoft.CodeAnalysis
 {
+    public interface ISeparatedSyntaxList
+    {
+        public SyntaxNodeOrTokenList GetWithSeparators();
+    }
 }

Usage Examples

The above evaluator can be rewritten as (assuming we only care about SeparatedSyntaxList<T>):

// given:
ISeparatedSyntaxList list;
SyntaxNodeOrTokenList nodeOrTokenList = list.GetWithSeparators();
return Use(nodeOrTokenList);

Alternative Designs

Retaining the design as-is.

Risks

Bloating the API with further interface abstractions.

@Rekkonnect Rekkonnect added Concept-API This issue involves adding, removing, clarification, or modification of an API. Feature Request labels May 19, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels May 19, 2024
@CyrusNajmabadi
Copy link
Member

I don't understand why an interface is necessary here. If you're using reflection, you can get to the GetWithSeparators() method easily and can call that.

@Rekkonnect
Copy link
Contributor Author

Yes but the point is to avoid discovering the method, or calling it dynamically like in the example. I find it more convenient to use that way, and avoiding concerns for future breaks.

@jaredpar jaredpar removed the untriaged Issues and PRs which have not yet been triaged by a lead label May 20, 2024
@jaredpar jaredpar added this to the 17.12 milestone May 20, 2024
@333fred
Copy link
Member

333fred commented May 20, 2024

I don't understand the use case here. Can you please elaborate on what the actual problem you're trying to solve is? Also, who would be implementing this interface? I just don't have enough information from this request to understand what you're trying to do or how this would actually help.

@Rekkonnect
Copy link
Contributor Author

I'm traversing the syntax tree and retrieving the syntax-related properties (SyntaxNode, SyntaxToken, etc.), which recursively traverses further down the tree. This may include properties like SeparatedSyntaxList<T>, though without having the static type of the property, I can't know the type argument. Therefore, to invoke GetWithSeparators() I have to either invoke a delegate by retrieving its invoker via reflection, or by relying on dynamic.

It would help having some way to expose the GetWithSeparators() method without knowing the type of syntax nodes held inside the SeparatedSyntaxList. What I thought is having an one-off interface called ISeparatedSyntaxList exposing this method, removing the need for using reflection/dynamic altogether.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented May 20, 2024

Therefore, to invoke GetWithSeparators() I have to either invoke a delegate by retrieving its invoker via reflection

But you said you were already using reflection here. So why not continue to do that? I don't get the desire to have a hybrid mode here.

@Rekkonnect
Copy link
Contributor Author

Writing good reflection is just tedious, that's all. If the API provided this interface, it would be trivial to invoke the method and retrieve its children nodes, assuming we have already evaluated that our object is of that type.

Right now I evaluate whether the object's type is a construction of the generic type SeparatedSyntaxList<T>, and then invoke the cached method delegate on it. That's much more tedious to write, and also worse in performance than a simple type check and virtual call.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented May 20, 2024

What's the performance scenario here where reflection is used at all?

Do you have a trace in your scenario where this is showing up as a substantive cost?

@Rekkonnect
Copy link
Contributor Author

Removing even a few reflection calls can be helpful. Even though it's being used extensively, it's better to avoid some small parts using reflection, if they could be designed otherwise.

I think that this is more of a type system problem in C# itself than it is for Roslyn. When you can't concretely type a type argument and want to invoke a method returning a fully known result, you can't use it statically unless you have a concretely statically typed construction of the generic type of your object. If this proposal is too hard to justify, we may as well ignore it.

@CyrusNajmabadi
Copy link
Member

Removing even a few reflection calls can be helpful.

I'd like to see data from this scenario demonstrating that though. How much actual wallclock time is being spent inside reflection here.

We don't ever do perf changes for hypothetical improvements. We need a real scenario demonstrating the problem. otherwise we can't validate taht the change actually solves the issue in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Concept-API This issue involves adding, removing, clarification, or modification of an API. Feature Request
Projects
None yet
Development

No branches or pull requests

4 participants