Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Utilize the new `ref readonly` language feature by tannergooding · Pull Request #89736 · dotnet/runtime · GitHub
Skip to content

Utilize the new ref readonly language feature - #89736

Merged
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911
Aug 2, 2023
Merged

Utilize the new ref readonly language feature#89736
tannergooding merged 8 commits into
dotnet:mainfrom
tannergooding:fix-85911

Conversation

@tannergooding

@tannergoodingtannergooding commented Jul 31, 2023

Copy link
Copy Markdown
Member

This resolves#85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

This is broken into 3 main commits:

  • in to ref readonly
  • ref to in
  • ref to ref readonly

As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:

  • An API was changed from in to ref readonly, users will now be asked to use in explicitly
  • An API was changed from ref to in, users will now be asked to use in or no longer specify ref

@ghostghost added needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners new-api-needs-documentation labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@tannergoodingtannergooding added area-System.Runtime.CompilerServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 31, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (v4.8.0-1.23378.8).

Author:tannergooding
Assignees:tannergooding
Labels:

area-System.Runtime.CompilerServices, new-api-needs-documentation

Milestone:-

[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(scoped in T source)
public static ref T AsRef<T>(scoped ref readonly T source)

@tannergoodingtannergoodingJul 31, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe to take ref readonly.

The general consideration is that most APIs on Unsafe are "unsafe" and many, such as Add, do not actually mutate the contents of the ref but rather simply adjust the ref to point to a new address.

If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset), then it basically has an implicit ref T AsRef<T>(ref readonly T source) built in.

The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe code. Consider the simple case below:

- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);

The downside is that any Unsafe operation can go from mutable to immutable ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe and to insert Unsafe.AsRef explicitly if it was intentional.

In an ideal world, we might have overloads that were ref T Add(ref T source, int offset) and ref readonly T Add(ref readonly T source, int offset). However, we can't due to them both being T& in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement

Comment on lines 333 to +334
uint address = PrivateAddress;
MemoryMarshal.Write(destination, ref address);
MemoryMarshal.Write(destination, in address);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we change this to:

MemoryMarshal.Write(destination,PrivateAddress);

? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8

{
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val);
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and elsewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Meaning this?

MemoryMarshal.Write(MemoryMarshal.AsBytes(destination),BitConverter.IsLittleEndian?0x65007500720054ul:0x54007200750065ul);// "True"

@tannergooding
tannergoodingforce-pushed the fix-85911 branch 3 times, most recently from ece204e to fe0dbafCompareAugust 1, 2023 15:16

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.

Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.

@tannergooding

Copy link
Copy Markdown
MemberAuthor

CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable.

Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy.

@mgravell

mgravell commented Sep 14, 2023

Copy link
Copy Markdown
Contributor

A bit late now, but a nasty side-effect of this is that it makes Unsafe.AsRef etc unusable from older lang-vers (and compilers);

with an up-to-date compiler but down-level lang-ver:

error CS8936: Feature 'ref readonly parameters' is not available in C# 10.0. Please use language version 12.0
or greater.

without an up-to-date compiler:

error CS1620: Argument 1 must be passed with the 'ref' keyword

(which of course it can't be; we're calling Unsafe.AsRef precisely because we don't have a ref)

At the time of writing, no devenv update is available on public preview that can use this feature, so: no Unsafe.AsRef for me until then :(

(I have 17.8.0 Preview 1.0 currently)

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: update API signatures to leverage ref readonly parameters

5 participants

@tannergooding@mgravell@IDisposable@jeffhandley@stephentoub