| I highly disagree with the interfaces criticism. Firstly You can literally just use one of the dozens of go lsps or code tools to search for API invocations to find what structs are passed/called into it. More importantly if you need to know you've written bad code. The entire point of an interface is that you SHOULDN'T need to know the underlying type. If you do you've violated the entire point. Just pass concrete ones. I've written Go for years and never had a problem with this, even in large open source projects like Kuberenetes. Secondly, the criticism about flipping return values order/meaning isn't a criticism of interface being structurally typed (https://en.wikipedia.org/wiki/Structural_type_system). If you return int, int and the second int "should be even", you should have defined a type "Even" and returned int, Even*. Systems which are structurally typed can demonstrate functional extensionality and (https://github.com/FStarLang/FStar/wiki/SMT-Equality-and-Ext...) and check whether you've flipped the arguments, which would be a more valid criticism (but such checks are expensive and conflict with compile time requirements). Also Java has the same problem, if you define two interfaces with the same method signature and a single class implements both you can't disambiguate. Thirdly, the structural typing has a huge advantage, namely looser coupling and more tightly defined interfaces. If you follow the "accept interfaces return structs" go idiom, you'll see why. An open source library that does so leaves their returned structs open to be used by consumer code, that itself uses interfaces, without modification required. This means most go code has small, tightly defined interfaces, where every function on the interface is invoked in the relevant function. For example if you have a library with this definition: type Baz struct {} func (b Baz) Foo(){}
func (b Baz) Bar(){} I can use Baz in my code like so: type Fooer interface {
Foo()
} func DoSomething(f Fooer) {
} And use the underlying library, while being decoupled from it, without having to modify it. Fourthly: You can explicitly say a type implements an interface... * A good study: https://blog.boot.dev/golang/golang-interfaces/ * In Idris we would do: even : Nat -> Bool
even Z = True
even (S k) = odd k where
odd Z = False
odd (S k) = even k int -> even
doubler a = 2 * a |