Embedding without specific methods?

I’m reading the current implementation of io.Copy for TCPConn. It has a struct called tcpConnWithoutWriteTo, which will cause the WriterTo casting from a io.Reader to fail. How and why does it work internally?

It won’t fail on casting. It will panic, when you try to call WriteTo

It will definitely not panic, the program will crash every time users invoke the io.Copy on TCPConn. I have a demo implemented the same pattern, the cast will just return nil, false instead of panicking:

package main

import "fmt"

type Fooer interface {
	Foo()
}

type Barer interface {
	Bar()
}

type base struct {
	msg string
}

func (b *base) Foo() {
	fmt.Println("Foo", b.msg)
}

func (b *base) Bar() {
	fmt.Println("Bar", b.msg)
}

type noFoo struct{}

type baseWithNoFoo struct {
	noFoo
	*base
}

func (b *baseWithNoFoo) Foo() {
	panic("Should not be called")
}

func check(b Barer) {
	f, ok := b.(Fooer)
	fmt.Println(f, ok)
}

func main() {
	b := &base{msg: "hello"}
	b.Foo()
	bNoFoo := baseWithNoFoo{base: b}
	check(bNoFoo)
}

Example Output:

[u@h d]% go run test.go 
Foo hello
<nil> false

Okay, I did my example wrong. It won’t cast. But there is an error in your example as well. Your panic code should belong to noFoo. I think it’s related to your digging into TCP and splicing here. It’s done this way, so io.Copy won’t cast it either. ReadFrom or standard copy algorithm will be used instead.

Yes, I know the effect, again, my question was why does it work, it’s pretty counterintuitive according to the language syntax and how it’s implemented internally.

func check(b Barer) {
why there is a Barer interface variable? Barer doesn’t include interface Fooer

I found out, that this is called ambiguous selector error. You can explicitly see it, if you for example try to change check argument interface. This error occurs with embedding when, at comp time, compiler cannot define which method is going to be used, when there are more than 1. In this case you need to “reload” the method via the base struct type to solve the issue. But since in this situation we operating interfaces, they are casting during runtime. Here we have copyBuffer function which accepts Reader as the interface, and tcpConnWithoutWriteTo follows this interface and can be used as the argument. But as soon as we try to cast it as a WriterTo we will fail due to ambiguity. Since we use value, ok := … this conversion will not panic at runtime, the error will be silent and simply return ok == false. As was discussed with splicing in another post, with TCP ReaderFrom should be used if possible or otherwise the default copy algorithm.

How does the io.Copy function determine whether it should optimize by using the WriterTo interface or fall back to a different method?