Should io.WriterTo "seek to the end"?

131 views
Skip to first unread message

Nigel Tao

unread,
Oct 26, 2022, 11:15:00 PM10/26/22
to golang-nuts
The io.WriterTo interface has come up in a code review discussion.

```
// WriterTo is the interface that wraps the WriteTo method.
//
// WriteTo writes data to w until there's no more data to write or
// when an error occurs. The return value n is the number of bytes
// written. Any error encountered during the write is also returned.
//
// The Copy function uses WriterTo if available.
type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}
```

Should WriteTo always modify receiver state, updating its internal "file position" by the number of bytes written?

Equivalently, if I'm re-using a WriterTo, passing it to multiple Copy calls, would you expect to need Seek(0, SeekStart) calls in between those Copy calls? This is a question of clarifying semantics. The compiler doesn't complain if WriteTo always wrote the entire contents (and didn't have a "file position").

---

In the standard library, every WriterTo implementation (with one exception), listed below, also "advances the file position". They all also implement io.Reader, even though, once again, the compiler doesn't enforce that every io.WriterTo is an io.Reader.

archive/tar.regFileReader
archive/tar.sparseFileReader
bufio.Reader
bytes.Buffer
bytes.Reader
net.Buffers
strings.Reader

There's also net/http.noBody, which doesn't explicitly update a "file position" field but it also represents a 0-sized "file" so in some sense it's always at the "end of the file".

The one exception is recordingConn in crypto/tls/handshake_test.go but it looks like its WriteTo method is more about "dump some debugging information" (it's in *_test.go code) than anything related to io.Copy.

Ian Lance Taylor

unread,
Oct 27, 2022, 12:36:53 AM10/27/22
to Nigel Tao, golang-nuts
On Wed, Oct 26, 2022 at 8:14 PM Nigel Tao <nige...@golang.org> wrote:
>
> The io.WriterTo interface has come up in a code review discussion.
>
> ```
> // WriterTo is the interface that wraps the WriteTo method.
> //
> // WriteTo writes data to w until there's no more data to write or
> // when an error occurs. The return value n is the number of bytes
> // written. Any error encountered during the write is also returned.
> //
> // The Copy function uses WriterTo if available.
> type WriterTo interface {
> WriteTo(w Writer) (n int64, err error)
> }
> ```
>
> Should WriteTo always modify receiver state, updating its internal "file position" by the number of bytes written?

I think that should be the default behavior, yes. Of course there may
be cases where that doesn't make sense. But in general I expect
WriteTo to behave like one or more calls to Read.


> Equivalently, if I'm re-using a WriterTo, passing it to multiple Copy calls, would you expect to need Seek(0, SeekStart) calls in between those Copy calls? This is a question of clarifying semantics. The compiler doesn't complain if WriteTo always wrote the entire contents (and didn't have a "file position").

Yes, I would expect that for cases where the WriterTo is seekable.

My reason for thinking this is that WriteTo basically exists to
support io.Copy, and in the absence of WriteTo io.Copy does advance
the file position of the source. So I think that for WriteTo to also
behave that way is the least astonishing choice.

Ian
Reply all
Reply to author
Forward
0 new messages