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

Switch to primary constructors in IDE layer #68299

Merged
merged 4 commits into from
Jun 14, 2023

Conversation

CyrusNajmabadi
Copy link
Member

No description provided.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels May 22, 2023
@CyrusNajmabadi
Copy link
Member Author

@jaredpar fyi.

@@ -8,22 +8,16 @@

namespace Microsoft.CodeAnalysis.Classification
{
public readonly struct ClassifiedSpan : IEquatable<ClassifiedSpan>
public readonly struct ClassifiedSpan(TextSpan textSpan, string classificationType) : IEquatable<ClassifiedSpan>
Copy link
Member

Choose a reason for hiding this comment

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

ClassifiedSpan

Wouldn't a record be better?

Copy link
Member Author

Choose a reason for hiding this comment

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

Let me see about updating the feature to support that afterwards!

_start = start;
_length = length;
}
private readonly int[] _buffer = buffer;
Copy link
Member

Choose a reason for hiding this comment

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

buffer

I don't think I'd keep the fields and also use primary ctor at the same time. Either, or. As it is now, both buffer and _buffer are in scope in all methods. If someone accidentally uses buffer instead of _buffer there is no error but the struct becomes larger.

Copy link
Member Author

Choose a reason for hiding this comment

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

Compiler will warn in that case. Assigning to field, but also using the parameter will warn about double storage :-)

Copy link
Member

Choose a reason for hiding this comment

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

I don't see the warning in Version 17.7.0 Preview 2.0 [33722.583.main]
image
Is it new?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@tmat tmat left a comment

Choose a reason for hiding this comment

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

🕐

@@ -8,13 +8,10 @@
namespace Microsoft.CodeAnalysis.Remote
{
[DataContract]
internal readonly struct RemoteServiceCallbackId : IEquatable<RemoteServiceCallbackId>
internal readonly struct RemoteServiceCallbackId(int id) : IEquatable<RemoteServiceCallbackId>
Copy link
Member

Choose a reason for hiding this comment

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

RemoteServiceCallbackId

record?

AdditionalProperties = additionalProperties;
CandidateReason = candidateReason;
}
public readonly CandidateReason CandidateReason = candidateReason;
Copy link
Member

Choose a reason for hiding this comment

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

Can we remove public field declarations and instead apply DataMember attributes to the generated fields?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. There is currently no way to get to the "Generated Fields" for primary constructors currently (we don't even guarantee they are fields on the type). There are future lang changes about being able to have a primary constructor, but be explicit if you want fields/props/etc. but they are not in 12.

Copy link
Member

Choose a reason for hiding this comment

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

You can't say [field: DataMember(...)] on the parameter?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not currently. but LDM def aware of the desire here. I'd expect something post C#12 on this. It's too useful/valuable IMO to not have a solution for.

_documentId = documentId ?? throw new ArgumentNullException(nameof(documentId));
_activate = activateIfAlreadyOpen;
}
private readonly DocumentId _documentId = documentId ?? throw new ArgumentNullException(nameof(documentId));
Copy link
Member

Choose a reason for hiding this comment

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

❔ How does it know when to create a backing field for the parameter, and when to not create it?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

So we never "create a backing field". The question is if we have to continue using the existing backing field, or if we can remove it. And the answer to that is "if the field is read/written in any way that would have differnet semantics from the parameter". A good example of that is simply:

public bool Equals(Whatever w)
   => _documentId == w._documentId;

Here, we cannot switch to a parameter, because then you cannot access the field anymore off of w.

public (string type, string layer)[] Metadata
=> _services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer)).ToArray();
=> services.Select(s => (s.Metadata.ServiceType, s.Metadata.Layer)).ToArray();
Copy link
Member

@sharwell sharwell May 24, 2023

Choose a reason for hiding this comment

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

📝 I really don't like that the fields are breaking naming conventions. It's going to make IntelliSense super annoying it types because you won't be able to type _ to filter to fields.

Copy link
Member Author

Choose a reason for hiding this comment

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

They're not fields (seriously. the language does not think of them as fields, or treat them in any way as fields). They are captured parameters :)

Copy link
Member

Choose a reason for hiding this comment

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

They are being used as a replacement for a field of the same purpose, so they are functionally equivalent. I predict this is going to be problematic for feature adoption due to the amount of code that needs to change as part of this (all references to a field with a _ prefix need to change in source control when they start referring to the captured parameter instead). Personally, I would rather not have primary constructors than to have the captures appear with this name.

@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review May 24, 2023 17:04
@CyrusNajmabadi CyrusNajmabadi requested review from a team as code owners May 24, 2023 17:04
@Cosifne Cosifne requested a review from a team as a code owner May 30, 2023 17:41
@CyrusNajmabadi
Copy link
Member Author

Blocked because of dotnet/roslyn-analyzers#6573. @sharwell @mavasani can you guys look into this.

@CyrusNajmabadi
Copy link
Member Author

@mavasani It looks like IDE0060 needs to be updated to understand primary constructors. Usages of PCs now results in tons of warnings like:

C:\github\roslyn\src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\Options\OptionDefinition.cs(102,41): warning IDE0060: Remove unused parameter 'serializer' (https://docs.microsoft.com/dot
net/fundamentals/code-analysis/style-rules/ide0060) [C:\github\roslyn\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj]

@CyrusNajmabadi
Copy link
Member Author

@mavasani @akhera99 i'm still getting:

src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CustomCodeActions.cs#L39
src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CustomCodeActions.cs(39,32): error CS9113: (NETCORE_ENGINEERING_TELEMETRY=Build) Parameter 'priority' is unread.

@CyrusNajmabadi CyrusNajmabadi merged commit c6111fc into dotnet:main Jun 14, 2023
@ghost ghost added this to the Next milestone Jun 14, 2023
@CyrusNajmabadi CyrusNajmabadi deleted the primaryConstructors branch June 14, 2023 20:27
@RikkiGibson RikkiGibson modified the milestones: Next, 17.7 P3 Jun 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants