Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chapter2: Interface conversions. Type assertions where the destination type is itself an interface. #34

Open
Quuxplusone opened this issue Sep 13, 2019 · 0 comments

Comments

@Quuxplusone
Copy link

Quuxplusone commented Sep 13, 2019

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant