What advantages are you thinking of? The obvious one is that you might want to stream the response rather than construct it in-memory at once. But as I read the parent (and as I've used similar interfaces in Rust), you don't have to have constructed the whole response with this interface. You can return something whose body is a stream.
If you return something whose body is a stream you still have to construct that thing, including the stream. And if you return something whose body is a stream you didn't fill in yet, you need to create entire async thunks or threads to fill that data in. You have also gained ~nothing.
You didn't outline the performance advantage. You've got "you need to create entire async thunks or threads to fill that data in", but that absolutely isn't true.
Let's look at how we might stream a file in response in go with the current model vs this new model, and you can point out where the performance difference is:
In the happy path, there's no difference in number of goroutines or anything, right? In both cases, this all runs in the goroutine or thread or whatever that the caller _already_ created for the request handler. What difference does it make if the request handler calls `io.Copy(response, body)` or if your function does, in both case it's the same goroutine/thread.
> You have also gained ~nothing.
You were the one that claimed you lose massive performance, and that's what we're asking about. The ergonomics are a separate thing from performance
Now do a body that requires literally any transformation or generation at all. Say, a series of DB query results as a CSV. (Oh, and make sure to cancel work when the request disconnects!)
Or heck, just try adding some error handling from the `io.Copy` result to what you have.
Just return an io.Reader that wraps the DB cursor and outputs CSV data... I fail to see what makes this so difficult. If the "mutable" approach involves passing down a mutable *http.ResponseWriter, then the dual approach of passing an io.Reader upstream is equivalent.
Try to write this, really. It’s such an unergonomic mess compared to for loop in the handler. It will also allocate a very complex reader that the actual version doesn’t need to.