Scanning an array of pointers to struct's with different type

The Go object model differs from classic OO, however it has been claimed that the Go model can fully emulate the classic model.
But here is an example that is easy in C++ but not in Go:

C++:

  struct Widget { ... };
  struct Button:Widget { ... };
  struct Slider:Widget { ... };

An array of pointers to Widgets can be created:

  Widget children[]={ &w1, &w2 .... };

When scanning this array, the real type of w1 etc. can be found using dynamic_cast<Button> and dynamic_cast<Slider>. One of them will return a non-null value.

This pattern is essential for any GUI toolkit. You need it in order to evaluate a mouse click, but it seems to be impossible in Go. I looked into the code of other GUI toolkits written in Go, and saw that no subclassing of the basic Widget struct had been used. A Widget struct simply contained all member variables that any subclass would ever need.

I think that this is an unsatisfactory solution. Is it possible to create something better?

W.Boeke

i guess you can use structs and interfaces like this (not real code, just playing).

That worked! I wanted an array of pointers, so I modified your code as follows:

a1:=make([]*Widget,0)

a1=append(a1, &b)
a1=append(a1, &s)

(*a1[0]).Draw()
(*a1[1]).Draw()

W.

It is almost never necessary to have a pointer to an interface value, and your program is not one of the exceptions. Moreover, you may be confused: You want struct pointers (that makes sense) but that does not mean the interface values need to be pointers too. An interface value can hold a pointer just fine.

a1:=make([]Widget,0) // No star

a1=append(a1, &b)
a1=append(a1, &s)

a1[0].Draw()
a1[1].Draw()

The calls to Draw will use the pointer-receiver methods of Button and Slider.

2 Likes

Hi Rob,

When I asked my question, I was a total newbee for Go. And when I answered geosoft1, I did’nt realize that his solution would not work, because you get no access to the contents of the original widgets. My proposed alternative was stupid.

In the meantime I solved my case by using an array of unsafe.Pointer’s, and casting them as needed. I found another GUI toolbox that seems to provide a complete solution, and it appears to use unsafe.Pointer’s all over the place.

The name of these pointers is kind of scary, but you really need them for a certain class of functionality. It would be nice if they were provided as a basic datatype, e.g. called ‘ptr’. Maybe the Go compiler could be made so clever as to perform the nesessary casting automatically. Another solution would be that one could store normal Go pointers of different type in one array.

I started an ambitious project, involving a GUI, realtime sound generation and a MIDI keyboard. I know how to do it in C++, and cgo will be my friend.

In my opinion your Go team created a kind of genius new language, very practical and solving a lot of inconveniencies of C and C++.

W.Boeke

Unsafe pointers are almost never the right answer to a programming question like this. You probably want the empty interface, or a proper interface type. Please read some more background material. Perhaps someone here will suggest a good place to start.

1 Like

Hi Rob,
Please don’t speculate on my ignarancy, but give me some working code. I believe that I expressed my problem clearly enough in my first post. I tried interfaces and also reflection, but only unsafe.Pointer could do the trick.

You’d want to use a type switch. See the end of main here:

https://play.golang.org/p/8B9H_j3NzO

You can change things around to use pointers on the concrete types. If you do, then you’d reference this in the type switch like *Slider or *Button.

As far as reading material goes, I’d recommend completing the tour. The type switch is covered there: https://tour.golang.org/methods/16

2 Likes

Hi Daniel,
You are my hero! It works!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.