I stumbled upon this one weird trick that Go devel...
# dev
a
I stumbled upon this one weird trick that Go developers apparently know. Say you want to log the actual values returned by a function. It's a complicated function, with several exits, and it's hard to see the right call in a debugger. What to do? • Modify the func to use named return values. • Right at the top of the func,
defer
a call to an anonymous func that logs relevant parameters and return values. • Because this is the first deferred func, it runs last -- if another deferred func also modified the return values, it still logs the right one. In my case it was a ReadAt implementation, so I started off by saying:
Copy code
func (f *myFile) ReadAt(buf []byte, off int64) (n int, err error) {
	defer func() {
		f.log().
		WithFields(logging.Fields{
				"off": off,
				"n": n,
				// BUG: do NOT log read values in released code
				"out", string(buf[:n])).
		WithError(err).
		Trace("[DEBUG] done!")
	}()
(Of course, this func logs data read so we marked a bug. But without
out
, we could keep it if needed).
👀 1
y
Why do you need named return values? AFAIK, the reason to use named return values is so that
defer
can change these variables (source and source). But
defer
can observe local variables just fine: see playground.
a
This way the defer can see the return values.
y
Just define local vars before the defer
Copy code
func (f *myFile) ReadAt(buf []byte, off int64) (int, error) {
    var err error
    var n int
    defer func() { /* log n and err */ }()
    // rest of the code
}
In general, I'd avoid named return values whenever's possible. I consider it harmful, and a very unneeded feature. For instance, there's a lint against naked returns (which, in fact, failed on your PR), and these are only possible because of named return values.