Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the 'scoped' keyword

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
}
like image 762
Twenty Avatar asked Aug 31 '25 18:08

Twenty


1 Answers

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.

like image 190
David L Avatar answered Sep 02 '25 08:09

David L