While looking at the source code of the new DefaultInterpolatedStringHandler
I noticed that the ReadOnlySpan
was annotated with the scoped
keyword. The only documentation I could find was here. However, I wasn't able to figure what the practical difference between the following code snippets would be. I assume that with the scoped
keyword the parameter is not allowed to be passed to a called method, nor to be returned. Even if this turns out to be true, what would be the practical use of it?
public void AppendFormatted(ReadOnlySpan<char> value)
{
// Omitted for brevity
}
// vs
public void AppendFormatted(scoped ReadOnlySpan<char> value)
{
// Omitted for brevity
}
As I mentioned in my comment, the purpose of the scoped
keyword for ref struct parameters is to allow stack allocated local variables to be passed to methods that do not capture the inbound ref struct or return the inbound ref struct from the method.
In the following highly trivialized example of the source you linked:
public ref struct Test
{
private Span<char> _chars;
private int _pos;
public Test()
{
_chars = new char[3];
_pos = 0;
}
public void AppendFormatted(ReadOnlySpan<char> value)
{
// Fast path for when the value fits in the current buffer
if (value.TryCopyTo(_chars.Slice(_pos)))
{
_pos += value.Length;
}
}
public Span<char> GetBuffer() => _chars.Slice(0, _pos);
}
if called from the following:
RunSpan();
void RunSpan()
{
var test = new Test();
Span<char> valuesToCopy = stackalloc char[1] { 'd' };
test.AppendFormatted(valuesToCopy);
}
it will throw the following errors
error CS8352: Cannot use variable 'valuesToCopy' in this context because it may expose referenced variables outside of their declaration scope error
CS8350: This combination of arguments to 'Test.AppendFormatted(ReadOnlySpan)' is disallowed because it may expose variables referenced by parameter 'value' outside of their declaration scope
However, as soon as you add the scoped
keyword AppendFormatted(scoped ReadOnlySpan<char> value)
you can call the method.
Note that scoped does NOT allow you to incorrectly return the parameter from the method! The following:
public ref struct Test
{
private Span<char> _chars;
private int _pos;
public Test()
{
_chars = new char[3];
_pos = 0;
}
public ReadOnlySpan<char> AppendFormattedBad(scoped ReadOnlySpan<char> value) => value;
public Span<char> GetBuffer() => _chars.Slice(0, _pos);
}
still returns the following error:
error CS8352: Cannot use variable 'ReadOnlySpan' in this context because it may expose referenced variables outside of their declaration scope
This functionality is tremendously useful when dealing with ref structs, since you often need to stackalloc a buffer that is passed to the method of a ref struct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With