Pungyeon/clean-go-article

Allocless way to check interface compatibility

vbauerster opened this issue ยท 4 comments

Interfaces part shows a way to check interface compatibility (fulfillment):

type NullWriter struct {}
var _ io.Writer = &NullWriter{}

Nothing wrong with above code, but for completeness sake it worth mention that we needn't allocate a new variable since any value of type *NullWriter will do, even nil:

type NullWriter struct {}
var _ io.Writer = (*NullWriter)(nil)

This explicit conversion works, because nil is typed in Go. Check this playground example.

I see! Thank you so much for taking the time to point this out! ๐Ÿ™ I actually thought that the compiler would optimise the _ variable away, but I suppose not?

I will write up a pull request for this ๐Ÿ˜„ Sorry for the late reply!

@vbauerster I had a look at this, using the build flag go build -gcflags '-m -m' ./main.go on the following code:

package main

import (
	"io"
)

type NullWriter struct{}

func (writer *NullWriter) Write(b []byte) (int, error) {
	return 0, nil
}

var _ io.Writer = (*NullWriter)(nil)
var _ io.Writer = &NullWriter{}

func main() {
	var _ io.Writer = &NullWriter{}
	var _ io.Writer = (*NullWriter)(nil)
	return
}

This gave me the following output:

# command-line-arguments
./main.go:9:6: can inline (*NullWriter).Write as: method(*NullWriter) func([]byte) (int, error) { return 0, nil }
./main.go:16:6: can inline main as: func() { var _ io.Writer; _ = &NullWriter literal; var _ io.Writer; _ = (*NullWriter)(nil); return  }
/var/folders/yk/2tnyv8g550zb0bg4vt0vn4l40000gn/T/go-build491024858/b001/_gomod_.go:6:6: can inline init.0 as: func() { keepalive_modinfo = __debug_modinfo__ }
./main.go:9:7: (*NullWriter).Write writer does not escape
./main.go:9:33: (*NullWriter).Write b does not escape
./main.go:17:20: main &NullWriter literal does not escape
./main.go:17:6: main &NullWriter literal does not escape
./main.go:18:6: main (*NullWriter)(nil) does not escape

This suggests that the compiler actually optimises the _ variables away. The output suggests that neither line 17 and 18 do not get allocated on the heap, and it seems to have completely ignored lines 13 and 14. So, I believe that there is no difference between the two methods?

Perhaps I am going about this all wrong though? If you have input on this, let me know, I would love to learn!

Thank you ๐Ÿ™

Frankly speaking I didn't think about _ part. But is sounds plausible that there is no difference because of compiler optimisation. So now I'm not sure if it worth mentioning the other way at all. ๐Ÿค”

Alright, I will keep the issue open, so that anyone can chime in and maybe give us a definitive answer on this ๐Ÿ˜„ Thanks again for opening the issue!