Update library change rules to reflect C# 12–14 language features#52976
Update library change rules to reflect C# 12–14 language features#52976
Conversation
Agent-Logs-Url: https://github.com/dotnet/docs/sessions/93a22581-57a9-46f8-a29e-41ef230a13e1 Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the .NET compatibility guidance for library authors by adding explicit change rules for newer C# language features that affect source and binary compatibility.
Changes:
- Adds guidance for
ref readonlyparameters,OverloadResolutionPriorityAttribute, andallows ref structgeneric anti-constraints in the Members section. - Adds guidance for C# 13
paramscollections signature changes, and C# 14extensionblock conversions in the Code changes section.
| - ✔️ **ALLOWED: Changing a `ref` parameter to [`ref readonly`](../../csharp/language-reference/keywords/method-parameters.md#ref-readonly-modifier)** | ||
|
|
||
| Changing a parameter from `ref` to `ref readonly` doesn't require callers to change their code. Call sites that pass arguments by `ref` work without modification. Unlike changing `ref` to `in`, this change doesn't allow callers to pass rvalues (non-variables), so existing call patterns remain valid. |
There was a problem hiding this comment.
The explanation says changing ref to ref readonly "doesn't allow callers to pass rvalues (non-variables)", but ref readonly parameters do allow passing non-variables at the call site (the compiler issues a warning, per the language reference). Consider rewording to clarify that ref readonly still requires an lvalue for ref/in arguments, and that passing an rvalue is possible only without a modifier (with a warning), so existing ref call sites remain valid.
There was a problem hiding this comment.
This is valid feedback. The clarification would be that changing from ref to ref readonly isn't breaking. But, changing from in to ref readonly can introduce warnings. That change from in should be considered a source breaking change because callers might set warnings as errors.
There was a problem hiding this comment.
Done in commit 105c954. Added a new ❌ DISALLOWED rule immediately after the ref → ref readonly ALLOWED rule: "Changing an in parameter to ref readonly". The explanation notes that call sites passing in arguments without the modifier (valid for in) will receive a compiler warning with ref readonly, and callers that treat warnings as errors will see a source breaking change.
…ptions Agent-Logs-Url: https://github.com/dotnet/docs/sessions/68ca8b08-2022-4927-a46a-9ba358612126 Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com>
BillWagner
left a comment
There was a problem hiding this comment.
There's one other new rule that should be considered:
In C# 13, ref struct types can implement interfaces. However, they can't be cast to those interfaces. So, as a result, adding an interface method with a default implementation is a breaking change for any ref struct that implements that interface.
It's probably a small risk, but should be at least "Requires Judgement"
| - ✔️ **ALLOWED: Changing a `ref` parameter to [`ref readonly`](../../csharp/language-reference/keywords/method-parameters.md#ref-readonly-modifier)** | ||
|
|
||
| Changing a parameter from `ref` to `ref readonly` doesn't require callers to change their code. Call sites that pass arguments by `ref` work without modification. Unlike changing `ref` to `in`, this change doesn't allow callers to pass rvalues (non-variables), so existing call patterns remain valid. |
There was a problem hiding this comment.
This is valid feedback. The clarification would be that changing from ref to ref readonly isn't breaking. But, changing from in to ref readonly can introduce warnings. That change from in should be considered a source breaking change because callers might set warnings as errors.
|
|
||
| - ❓ **REQUIRES JUDGMENT: Adding <xref:System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute> to an existing overload or changing its priority value** | ||
|
|
||
| The <xref:System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute> affects overload resolution at the source level: callers that recompile might resolve to a different overload than before. The intended use is to add the attribute to a new, better overload so the compiler prefers it over existing ones. Adding it to an existing overload or changing the priority value on an already-attributed overload is a source breaking change because callers that recompile might change behavior. |
There was a problem hiding this comment.
| The <xref:System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute> affects overload resolution at the source level: callers that recompile might resolve to a different overload than before. The intended use is to add the attribute to a new, better overload so the compiler prefers it over existing ones. Adding it to an existing overload or changing the priority value on an already-attributed overload is a source breaking change because callers that recompile might change behavior. | |
| The <xref:System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute> affects overload resolution at the source level: callers that recompile might resolve to a different overload than before. The intended use is to add the attribute to a new, better overload so the compiler prefers it over existing ones. Adding it to an existing overload or changing the priority value on an already-attributed overload can be a source breaking change because callers that recompile might change behavior. |
Agent-Logs-Url: https://github.com/dotnet/docs/sessions/c42a9e1b-00e8-4edd-8308-09ef83a8ca84 Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com>
Done in commit 105c954. Updated the existing ❓ REQUIRES JUDGMENT "Adding a member to an interface" rule to explicitly address the C# 13 scenario. The body text now explains that |
Clarified the explanation regarding breaking changes when adding overloads that preclude existing ones.
The compatibility rules article (
library-change-rules.md) had no guidance for several newer C# language features that affect binary/source compatibility for library authors.New rules added
Members section
ref→ref readonlyparameter (C# 12): Existingrefcall sites compile without change; unlikeref→in,ref readonlydoesn't silently accept rvalues—it issues a warning instead.in→ref readonlyparameter: Call sites passing arguments without theinmodifier (valid forin) will receive a compiler warning withref readonly. Callers that treat warnings as errors experience a source breaking change.OverloadResolutionPriorityAttribute(C# 13): Intended for new overloads; applying to existing overloads or changing an existing priority value can be a source break.allows ref structto a type parameter (C# 13): Expands accepted type arguments; existing callers unaffected.allows ref structfrom a type parameter (C# 13): Restricts accepted type arguments; breaks callers usingref structtype arguments.Code changes section
paramsparameter (C# 13): Recognized collection types includeSpan<T>,ReadOnlySpan<T>, specific interface types, and struct/class types that implementIEnumerable<T>with a parameterless constructor and instanceAddmethod. Changing the collection type alters the IL signature—binary break.extensionblock syntax (C# 14): Both forms emit identical IL; binary and source compatible.Updated guidance
ref structtypes can implement interfaces but can't fall back to default implementations. Adding any default instance member to an interface implemented by aref structis a source breaking change for those callers.Internal previews