182 karma · joined June 3, 2011
maps.Collect(xiter.Filter2(func(k, v int) bool { return k%2 == 0 }, maps.All(m)))I'm not personally concerned about examples like os.Open, where the result must be used. Sure, you can ignore the error. But a failure will show up very quickly. I'm not saying that this is not an issue at all, but I believe it's a less important one.
Part of the reason for Go's behavior is the idea that "errors are values" (https://go.dev/blog/errors-are-values). And part of it is that the simple fmt.Println("Hello, world") doesn't require any error handling. And part of it is the desire to make error handling clear and explicit in the program, even if the result is verbose.
(Separately, I'm not entirely sure what you mean when you say that Go doesn't use interface types for its error handling, since the language-defined error type is in fact an interface type.)
There is a lot of discussion of sum types in Go at https://go.dev/issue/19412.
type A[T] int
Is that a parameterized type named A with a type parameter T, or is it a definition of an array named A whose length is T?
Separately, it's nice that type parameter lists use the same syntax as non-type parameter lists.
The dev.go2go branch will not be merged into the main Go development tree. The branch exists mainly to support the translation tool, which is for experimenting with. Any work that flows into the main Go development will go through the code review process as usual.
I agree that unmaintained libraries that don't adapt to modules could be a problem. We'll have to see what happens.
Another approach would be to use two different map implementations, and use a less efficient one for older code that used an interface type as a map key.
It's an interesting example, though. You're right: if there is an old language feature that can not be supported by a newer runtime, then there needs to be some sort of shim to let the older code keep working. That necessity may prevent us from making certain sorts of language changes.
I'm not sure that Go is a language in which higher-level abstraction is appropriate. After all, one of the goals of the language is simplicity, even if it means in some cases having to write more code. There are people right here in this discussion arguing that contracts adds too much complexity; higher order polymorphism would face even more push back.
A similar issue arises in C++; the C++ standard says that there is an implementation defined limit on the total depth of recursive instantiations. Perhaps Go should do something similar.
Every language decision has pluses and minuses. I think most Go programmers feel that this problem is fairly hypothetical because it doesn't seem to come up for most people in real code. But, you're right, it's possible for it to come up. Every language decision has minuses, including this one.
But the pluses outweigh the minuses, so this is not going to change. Sorry.
(Personally, I don't mind the ongoing discussions about generics in Go, I just wish they were less repetitive. It's very easy to say "add generics to Go!" It's a little bit harder to actually do it well.)
I think the essay is entirely correct: there are certain patterns that are difficult to write in Go. It's hard to write generic code that merges two channels into one. It's hard to write generic code that acts as a future.
But it's easy to write type-specific code to perform those operations. Most Go programs do not need to merge channels of many different types. So people simply write the code they need when they need it.
This is not to say that there is no use for generics. There is clearly a use for generics, and examples using channels are among the strongest use cases. I'm just trying to answer your question about what Go developers actually do.