Separated out of https://github.com/dotnet/corefx/issues/21281 for tracking purposes.
```C#
namespace System.IO
{
public class TextReader
{
public virtual int Read(Span
public virtual ValueTask
public virtual int ReadBlock(Span
public virtual ValueTask
…
}
public class TextWriter
{
public virtual void Write(ReadOnlySpan<char> source);
public virtual Task WriteAsync(ReadOnlyBuffer<char> source, CancellationToken cancellationToken = default(CancellationToken));
public virtual void WriteLine(ReadOnlySpan<char> source);
public virtual Task WriteLineAsync(ReadOnlyBuffer<char> source, CancellationToken cancellationToken = default(CancellationToken));
…
}
}
```
EDIT 7/25/2017: Updated with CancellationTokens per API review.
Thanks @stephentoub. Will work on this.
Just to make sure I understand correctly... In the opening comment for API to be added, Read and ReadBlock work with Span<char> whereas ReadAsync and ReadBlockAsync work with Buffer<char>. I guess these differences are just for illustrative purpose and actually all four methods are to be provided for Span<char> as well as Buffer<char>. Likewise for Write* methods...?
I guess these differences are just for illustrative purpose and actually all four methods are to be provided for Span
as well as Buffer
No, these are the actual APIs. The synchronous ones take spans, the asynchronous ones take buffers.
Ok. I believe that is out of the fact that spans are on stack (?) and hence can be used in sync APIs only whereas buffers are on heap and hence can be used in async APIs. But then buffers could be used in sync versions as well right... But one could create a span on buffer and use it in sync API...
I'm still not clear about spans and buffers, the new ways... Where can I get to read up more? Google doesn't show up much...
I believe that is out of the fact that spans are on stack
Yes. Spans are a ref-like type, which comes with various constraints, including that it can't live on the heap. And that means it can't be an argument to an asynchronous method that might need to capture that argument to live on the heap for the duration of the operation.
But then buffers could be used in sync versions as well right
Yes. But a) spans are cheaper than buffers, and b) if you have a span and a method takes a buffer, you'd have no way to call it. In that sense spans are sort of a universal receiver: if you have a method that takes a span, you can call it if you have either a span or a buffer, but if you have a method that takes a buffer, you can't call it with a span. Thus, wherever possible, we'd ideally like methods to take spans.
@stephentoub I'm unable to locate the tests / performance tests for TextReader / TextWriter. Please let me know where I can find them...
I'm doing this work in parts. First TextReader and TextWriter, followed by StringReader/StringWriter/StreamReader/StreamWriterand then theBuffer` based overloads...
@stephentoub bumping up the thread...
Between I am working on adding new overloads in StreamReader which has the apis working on char buffer all the way down to (abstract) System.Text.Decoder and its various implementations in System.Private.CoreLib. Likewise is the case for Write* overloads that use Encoder implementations. So do we want to add Span based implementations in the Encoder / Decoder interface and implementations (CoreLib) as well such that,
a. Span<char> based overloads in Text/Stream/String Reader/Writers use the span based overloads in Decoders and Encoders.
b. char based overloads in Text/Stream/String Reader/Writers start using the span based overloads in Decoders and Encoders.
Being a big change, wanted to check if I am thinking right.
Quick dirty alternative may be to call the existing char buffer based overloads in Text/Stream/String Readers/Writers inside the Span<char> based overloads with copy to-and-fro span and buffer. That would introduce the Span<char> based overloads in right places but would be super inefficient.
Appreciate your inputs.
I'm unable to locate the tests / performance tests for TextReader / TextWriter.
It's possible there's a test gap here. They should be in System.IOtests in corefx. @JeremyKuhne? @ianhays?
So do we want to add Span based implementations in the Encoder / Decoder interface
They already exist. Double check that your repo is up-to-date. They were added a week or two ago.
@stephentoub Thanks. Yup. Updating the repo, I got the Encoder / Decoder interface implementation. Mine was a bit more stale than two weeks. Also I got the Stream/String Reader/Writer tests in the Test project in System.IO. I don't think I find for TextReader/Writer...
It's possible there's a test gap here. They should be in System.IOtests in corefx. @JeremyKuhne? @ianhays?
iirc there aren't any specifically for TextREader/TextWriter and the justification was that StreamReader/StreamWriter tests provide coverage for them. Really we should have some tests specifically for TextReader/TextWriter that use a basic/dummy implementation.
Most helpful comment
Yes. Spans are a ref-like type, which comes with various constraints, including that it can't live on the heap. And that means it can't be an argument to an asynchronous method that might need to capture that argument to live on the heap for the duration of the operation.
Yes. But a) spans are cheaper than buffers, and b) if you have a span and a method takes a buffer, you'd have no way to call it. In that sense spans are sort of a universal receiver: if you have a method that takes a span, you can call it if you have either a span or a buffer, but if you have a method that takes a buffer, you can't call it with a span. Thus, wherever possible, we'd ideally like methods to take spans.