It's quite possible this is covered in Chapter 2 or elsewhere, and I missed it, because I am lazy. If so, apologies!
Based on my C++ background, I believe I completely understand how Go handles your type-assertion example here. It can just, as you say, compare Eface._type with type.uint32.
But I cannot fathom how the following code works!
type Craft interface { Float() }
type Car struct {}
type Boat struct {}
func (c Boat) Drive() {}
func (c Boat) Float() {}
func (c Car) Drive() {}
var vface interface { Drive() }
var cface interface { Float() }
func main() {
b := Boat{}
vface = b
cface = vface.(Craft)
}
On the line cface = vface.(Craft), all the compiler knows about vface is that it is some kind of Vehicle. (Incidentally, its _type compares equal to type.Boat; but nobody said anything about Boat on this line, so that can't be relevant to anything.) So how does the runtime know how to convert an arbitrary Vehicle into a Craft?
If you initialize b := Car{} instead, then you get panic: interface conversion: main.Car is not main.Craft: missing method Float at runtime — which is exactly what I would expect — but, I don't understand how the runtime figured that out. Does the _type structure for Car contain a list of the names and signatures of every one of its methods, and then the interface-conversion code walks through that whole list at runtime to collect the needed methods to populate a Craft itab (or panic)?
In C++ terms, your Eface.(uint32) example is simply a std::any_cast — relatively cheap — but the vface.(Craft) example seems much wilder, much more dynamic and costly — so costly that it can't be done at all in C++. Is that right?
It's quite possible this is covered in Chapter 2 or elsewhere, and I missed it, because I am lazy. If so, apologies!
Based on my C++ background, I believe I completely understand how Go handles your type-assertion example here. It can just, as you say, compare
Eface._type
withtype.uint32
.But I cannot fathom how the following code works!
On the line
cface = vface.(Craft)
, all the compiler knows aboutvface
is that it is some kind ofVehicle
. (Incidentally, its_type
compares equal totype.Boat
; but nobody said anything aboutBoat
on this line, so that can't be relevant to anything.) So how does the runtime know how to convert an arbitraryVehicle
into aCraft
?If you initialize
b := Car{}
instead, then you getpanic: interface conversion: main.Car is not main.Craft: missing method Float
at runtime — which is exactly what I would expect — but, I don't understand how the runtime figured that out. Does the_type
structure forCar
contain a list of the names and signatures of every one of its methods, and then the interface-conversion code walks through that whole list at runtime to collect the needed methods to populate aCraft
itab (or panic)?In C++ terms, your
Eface.(uint32)
example is simply astd::any_cast
— relatively cheap — but thevface.(Craft)
example seems much wilder, much more dynamic and costly — so costly that it can't be done at all in C++. Is that right?