If Go is really so bad, why don’t Go programmers use e.g. Rust? I’m sure they’d cite things like:
- Compilation time is much faster in Go.
- Complexity. Rust is a highly complex language even for me as a C++ programmer. For those who are new to compiled languages they are certainly going to choose Go over Rust
- GC definitely has development time benefits over a borrow checker if you can afford the extra CPU headroom and memory usage
- Go’s concurrency model is more appealing to many people
The real question is, why is there not a “Go but designed by sane people” language?
> The real question is, why is there not a “Go but designed by sane people” language?
The fact is that the JVM and .NET platforms would almost surely do better for anything that golang is considered for, but there's a lot of hype and companies want to attract programmrs.
Rust is complex due to the inherent complexity of being a low-level language.
So now the static expressivity of the type system is compromised in the name of runtime introspection. Reminiscent of how when Java added generics, runtime introspection ended up totally blind to them due to erasure.
This seems like the result of not taking care to account for the possible future addition of generics when originally designing the language — it was always well understood that they’d be a likely later addition to the language. The ability to check if a value satisfies an interface at runtime doesn’t seem all that critical, although I could be missing something, I’m not a regular user of the language.
One place it's absolutely critical, and certainly the most common by number-of-calls even if people don't think about it, is `fmt` functions that check to see if the type implements `String() string`.
An idiom found in many data-shuffling libraries is to accept a small interface like `io.Writer`, but have fast-paths if the type also implements other methods. E.g. https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/io...
It's a little annoying but I don't think it's as bad as Java's erasure. We're still very early in idiomatic Go-with-generics so maybe we'll see a huge impact from this limitation later, but most times I see people wanting generic method parameters, they've got a design in mind which would be horribly inefficient even if it was valid. If you are going to box everything and generate lots of garbage, you might as well write Java to begin with.
package p1
type S struct{}
func (S) Identity[T any](v T) T { return v }
package p2
type HasIdentity[T any] interface {
Identity(T) T
}
package p3
import "p2"
// Because parameter v might be (and in this case is) coerced into
// p2.HasIdentity[int], this function gets a type annotation in the compiler
// output indicating that callers should pass a p2.HasIdentity[int] interface
// reference for v if it exists, or nil if it doesn't, as an additional
// argument.
func CheckIdentity(v interface{}) {
if vi, ok := v.(p2.HasIdentity[int]); ok {
if got := vi.Identity(0); got != 0 {
panic(got)
}
}
}
package p4
import (
"p1"
"p3"
)
func CheckSIdentity() {
p3.CheckIdentity(p1.S{})
}I think it would be terrible to include in the language because of the inconsistencies, but it is possible to make the two examples you listed as typical cases of interface->interface coercion work with generic methods, ugly as it may be.
"No way to require pointer methods" has been much more frustrating to work around. Even the part that works ("Pointer method example") sucks right now because type-type inference was disabled shortly before the 1.18 release pending some bugs. Hopefully once the basic ergonomics are back this can be reconsidered.