And I think the idea of interfaces is fine, just not Go's implementation. Interfaces could be a compile-time, duck-typed abstraction with very basic runtime reflection (basically just a type-assertion switch), but they're not. They instead leaned way too hard into it and made interfaces a value type, when they really shouldn't be like that at all.
The vast majority of the time, I just want to pass a concrete type as an abstract type, and occasionally check if that abstract type has any extra features (e.g. does this io.Reader have a Close() error?). I've done runtime reflection a few times in Go, and every time it was a disgusting hack.
Rust goes the opposite direction and forces the developer to explicitly opt in to traits. That's a bit more annoying, but it makes for much more scalable software. I don't know how many times I accidentally didn't implement an interface fully and my types didn't come through until I ended up with forcing the compiler to help out: var_someInterface= concreteType{}. I ended up doing that pretty much everywhere because I ran into so many times I accidentally didn't fully implement a type.
I still think Go is a fine language, I just don't think it scales well to larger applications. And that's what I want to build, so I don't use Go much anymore.
Yeah, no worries.
And I think the idea of interfaces is fine, just not Go's implementation. Interfaces could be a compile-time, duck-typed abstraction with very basic runtime reflection (basically just a type-assertion switch), but they're not. They instead leaned way too hard into it and made interfaces a value type, when they really shouldn't be like that at all.
The vast majority of the time, I just want to pass a concrete type as an abstract type, and occasionally check if that abstract type has any extra features (e.g. does this
io.Reader
have aClose() error
?). I've done runtime reflection a few times in Go, and every time it was a disgusting hack.Rust goes the opposite direction and forces the developer to explicitly opt in to traits. That's a bit more annoying, but it makes for much more scalable software. I don't know how many times I accidentally didn't implement an interface fully and my types didn't come through until I ended up with forcing the compiler to help out:
var _ someInterface = concreteType{}
. I ended up doing that pretty much everywhere because I ran into so many times I accidentally didn't fully implement a type.I still think Go is a fine language, I just don't think it scales well to larger applications. And that's what I want to build, so I don't use Go much anymore.