Your proposed signature has a little problem and that is that when calling

    result, err := reader.Read(nil)

the Read method doesn’t know how many bytes it should read.

The incoming buffer parameter actually serves two purposes. First is to
provide a place for storage. The second is to tell how many bytes should be
read.

If you want to read all the bytes from a reader, you can use
https://golang.org/pkg/io/ioutil/#ReadAll

If you want to read N bytes into a freshly allocated buffer, you can make a
helper function:

    func ReadNBytes(r io.Reader, n int) (result []byte, err error) {
        result = make([]byte, n)
        n, err := r.Read(result)
        return result[:n], err
    }

On Fri, 6 Sep 2019 at 00:48 Tom Payne <twpa...@gmail.com> wrote:

> Dave Cheney has written (yet another) excellent blog post on Go, on the
> subject of API design and caller-controlled allocations:
>
> https://dave.cheney.net/2019/09/05/dont-force-allocations-on-the-callers-of-your-api
>
> In this he compares two possible signatures for the io.Reader.Read method:
>   func (r *Reader) Read(buf []byte) (int, error)
>   func (r *Reader) Read() ([]byte, error)
> and makes a very good case for why the first, albeit trickier to use, is
> the better API. The post also sets up a false dichotomy/straw man argument,
> comparing only two signatures when there are other alternatives too.
>
> What about the following API:
>   func (r *Reader) Read(buf []byte) (result []byte, err error)
> If the buf argument is non-nil then buf is used to store the result,
> len(result) == the int returned by the actual Read(buf []byte) (int, error)
> method.
> If the buf argument is nil then a new []byte is created and returned, i.e.
> the allocation is done by Read and the method is as easy to use as Read()
> ([]byte, error).
> The semantics of the error return remain the same (i.e. Read might return
> both some bytes read and an error), but that is orthogonal to the memory
> allocation.
> An example of this pattern is here
> <https://github.com/twpayne/go-polyline/blob/master/polyline.go#L68-L76>.
>
> Given that slices are small and cheap to copy (a pointer to the data, a
> length, and a capacity) what are the downsides to using
>   func (r *Reader) Read(buf []byte) (result []byte, err error)
> as a method?
>
> I am not suggesting that we change io.Reader (that would break
> everything!), just looking for input into good Go API design.
>
> This would be a comment on Dave's fantastic blog, but the blog does not
> have comment functionality, so I'm asking here, and I know that Dave lurks
> here too.
>
> Cheers,
> Tom
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/8ffb9828-c6e2-47de-bca1-ef6988f081e8%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/8ffb9828-c6e2-47de-bca1-ef6988f081e8%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAO6k0uvEZgHm9ppQ8sA1K-M8fA2WENf0tJG1KyTov7PXAt6GcQ%40mail.gmail.com.

Reply via email to