5 ms·
The thing that tripped me up was you can't pass lists of interfaces across function boundaries. It's confusing when you're starting out
by micah_chatt 10y ago
The thing that tripped me up was you can't pass lists of interfaces across function boundaries. It's confusing when you're starting out
- zellyn 10y agoCould you post an example of what you're talking about? Passing slices of interface values works just fine. https://play.golang.org/p/9CWzdnRb8U https://play.golang.org/p/9CWzdnRb8U Is this what you mean? Trying to pass a []fooint as a []Fooer doesn't work: https://play.golang.org/p/dmFfr0Exnk https://play.golang.org/p/dmFfr0Exnk - that doesn't work in many languages, which is sad, but is for reasons that make sense if I think about what it would actually be doing under the covers: an interface value needs to store type information and/or a pointer to some kind of function pointer table, so you'd have to recreate that for each list element if you change the type of the list.
- adonovan 10y agoAlso, a []Fooer supports the operation of storing any element assignable to Fooer, whereas a slice []fooint does not support that operation, so it makes sense that a []fooint cannot be used anywhere a []Fooer can.
- zellyn 10y agoThat is a nice way of putting it.
- deleted 10y ago[deleted]
- camus2 10y ago> that doesn't work in many languages, it does when the language has generics. You in fact wouldn't need 2 types []fooint and []Fooer but a single List<T Fooer> , as long as fooint implements Fooer. So with Go you end up writing functions that convert types manually. The 1000's time you do this, it starts getting a bit tiresome.
- zellyn 10y agoWell, Java has generics, but you still can't do this same thing: http://stackoverflow.com/questions/1115230/casting-object-array-to-integer-array-error http://stackoverflow.com/questions/1115230/casting-object-ar... I agree that having generics in Go would be fantastic, and I'm excited at rsc's articulation of why. But they don't completely solve this problem.
- camus2 10y agoBut with Java the point is that you'd approach the issue differently without being overly verbose just like Go. I mean my example is clear. You wouldn't have to cast anything provided you use generics at first place.
- majewsky 10y agoI'm not convinced. Suppose that a struct type Foo implements an interface Fooer, and I want to do something like this: func workOnInterfaceList(foos []Fooer) {...} func workOnStructList(foos []Foo) { workOnInterfaceList(foos) //compile error: cannot cast []Foo into []Fooer } It's obvious how to resolve this: func workOnStructList(foos []Foo) { foos2 := make([]Fooer, len(foos) for idx, foo := range foos { foos2[idx] = foo //casts Foo into Fooer implicitly } workOnInterfaceList(foos2) //ok now } Why can the compiler not insert this automatically (esp. given that [] is a builtin type)? But then again, Go has a reputation of making you write the same code over and over again, so I'm not surprised. (And I say that as an empathic supporter of Go.) As an aside, if you think this example is artifical, here's it happening in real-world code: https://github.com/majewsky/sqlproxy/blob/f5b297e7dce14c045323881f272b97a3fdfb74c3/driver.go#L260-L266 https://github.com/majewsky/sqlproxy/blob/f5b297e7dce14c0453...
- zellyn 10y agoI'm not convinced either. It's not clear that the compiler should do that. You just allocated a new array, and (may have) made copies of the values in the original array. Reordering the new array will not reorder the original one. etc. etc. It's not clear to me what you'd want to do in every case, let alone to a compiler. Just curious: did you mean empathic or empathetic or emphatic? :-)
- majewsky 9y agoOh dear, of course I meant "emphatic". I'm certainly not a Betazoid. :)
- echlebek 9y agoYour code doesn't contain the definition of Foo and Fooer but I'll assume Foo is a concrete type and Fooer is an interface that Foo satisfies. The reason that []Foo is not the same as []Fooer is simple: they are different data types. They have a different layout in memory. Internally, an interface value is a pair of pointers. One points to the concrete value, and the other points to the concrete type of the value. The compiler needs to know the size of the things it's working with in the case of slices, because it needs to know how to compute offsets for indexing and iteration. It could make an implicit copy at runtime, but that could trigger a costly operation that would be invisible to the user. Go wants expensive operations to be visible, so you have to make the copy yourself.