I like Go very much, a huge role plays its simplicity. In my career, I have been much more often bitten by having to deal with the complexity of a language then by not being able to do things, because a language feature is missing. That is, why I like Go so much. It strikes a great balance between important high-level features (GC, first class functions and closures) and still being a simple language (like Scheme is, in a sense they are very comparable in my eyes). The interface concept is great for covering a lot of cases. That is, why so far, I have not missed generics much and was rather reluctant to the constant wishes to add them to the language.
On the other side, there are cases, even if they are not very frequent, where generics do help a lot. Just the new slices package allone almost justifies the addition of generics. Furthermore, the proposal looks very much Go-like. As a consequence, I am quite looking forward to try them out and used responsibly[1], they can be a great addition to the Go universe.
1: I think the situation is somewhat similar to Lisp macros. Normally, a codebase rarely requires macros and readability is better, if you avoid creating too many macros. But occasionally there are situations, where using a macro tremendeously increases code quality. Both implementation and readability-wise. There macros should be used and it is great to have them available.
I roll my eyes when someone claims "I learned Go over the weekend". It's one thing to learn basic syntax, and completely another to learn the customs of your new environment so most can understand what you are doing.
Go is one of the hardest languages to learn. First of all, some concepts in it are very different from "mainstream" languages, and it takes a while to get used to them.
Simple things that exist in almost every other ecosystem can be absent in Go. Want to run setup code before your test suite? You on your own, buddy. And, oh yeah, 2/3 of your code will be `if err` statements, because exceptions are passé.
I learned it by seeking out good Go codebases, which are incredibly rare. Hashi's Terraform comes to mind.
Infamously, the early Kubernetes code was a nightmare because it lifted and shifted Java idioms and that was at the company that invented the Language.
All this to show that Go is not a simple language to do well, so let's dispense with that myth.
It has its uses, but having done it, I would never recommend Go for a greenfield project in my place of work - there are very few rules that come with it, and it requires tons of coordination and discipline among a team. And if you have to work with 2 or 3 other people who have strong opinions on how to do things in Go, watch out.
I have not claimed you can "learn Go over the weekend". Not in a deeper sense where you could expect to design large projects and take the right decisions.
But you can get a pretty good basic Go intro in a few days and be pretty productive after that. It isn't that different from most languages and has a rather small core. Of course, it helps if you have Scheme experience, to understand all the power of high order functions etc.
IMO, “learning the language” and “getting used to it” are different things.
The first is a purely theoretical exercise, the second a applied one that involves not only the language but also its ecosystem (implementation(s), library of functions and tooling)
I used to really hate Go's attitude to generics and type system features in general. I still do, but I appreciate that it's a matter of taste, and that different people have different tolerances for language complexity. People who like simplicity can use Go and people who like type systems can use Rust.
Super excited for this. If you haven't checked out the latest proposal, here's an example of what Option/Result box types might look like (obviously not ready for release, just an experiment):
> Viewing and/or sharing code snippets is not available in your country for legal reasons. This message might also appear if your country is misdetected. If you believe this is an error, please file an issue.
Shame as a species we can't even share information (literally bits on the wire) globally, even if tangible goods and movements are circumscribed by political borders.
> Each Unwrap() call needs two OK() calls? Letting Unwrap return OK would be better?
That would rather miss the point as you'd be converting the type-safe result to an unsafe version?
Go doesn't have pattern matching or any "structural" construct which would allow performing this in a single step, so the alternative would be to use HoFs and while Go has them they're quite verbose e.g.
func (o Option[T]) Then(then func(T)) {
if o.OK() {
then(*o.value)
}
}
a.Then(func (v int) { fmt.Printf("\tvalue = %d\n", v) })
which is… less than great.
An safe other option would be a method mapping to a slice of 0..1 element and you'd use a `for range` as an `if` but that seems way to clever, similar to Scala's comprehensions over everything which I rather dislike.
Also sadly the current proposal has no facilities for methods generic in their arguments independently from the subject, so no `Map` method.
Reading the specification (https://go.googlesource.com/proposal/+/refs/heads/master/des...) this flows from the type being declared generic, Go will (currently at least) require the receiver to be similarly generic, no specialisation, and no method constraints:
> Generic types can have methods. The receiver type of a method must declare the same number of type parameters as are declared in the receiver type's definition. They are declared without any constraint.
// Push adds a value to the end of a vector.
func (v *Vector[T]) Push(x T) { *v = append(*v, x) }
> The type parameters listed in a method declaration need not have the same names as the type parameters in the type declaration. In particular, if they are not used by the method, they can be _.
Because it can only be a type parameter. There is no specialization. (TBH I think that's a mistake because if prevents a solution to the Expression Problem.)
No, Go doesn't have discriminated/tagged unions or valued-enumerations or whatever you want to call them, but generics let you hack them in without much trouble. Personally I'd take ADTs over generics any day, but it's not a dichotomy maybe we'll still get them some day.
I guess I'm understanding some of the concerns. It does make the code harder to understand. I wish they would use the angle brackets to match other languages.
This is actually my first week using go (from years of C++/Swift/js/etc) and I’ve been very impressed with the module system and simplicity so far. I’d definitely encourage others to try it if they haven’t.
As for generics, Go’s lack of function overloading and arg default values is really interesting. It ensures that a function is always easily found as it’s the only thing in the module with that name. I’ll be curious to see if generics are easier to follow without function overloading. It will still be only in one place, where as in C++ you could have hundreds of functions with the same name across many libraries and you just have to hope your ide knows which to step into.
> As for generics, Go’s lack of function overloading and arg default values is really interesting. It ensures that a function is always easily found as it’s the only thing in the module with that name. I’ll be curious to see if generics are easier to follow without function overloading.
There are already a number of langages with generics and without overloading (or defaults). Haskell, ocaml, rust, …
True of OCaml and Rust (and many others), but Haskell certainly has overloaded functions through type classes. In fact, once OCaml gets implicit modules, this won't be true anymore of OCaml either.
Not excited about this feature, I guess we'll see how frequently it shows up in unwanted places. Generics in C++ really damage the readability of the code sometimes, maybe the go devs have found a better way.
Very skeptical, but the go devs have given me plenty of pleasant surprises before, maybe we get another one here.
The key to readability is programming with readability in mind. Sure, languages play some part in that, but 90% of it is the programmer. Go is simple right now, and generics do complicate it, but even with the simplicity that Go has, people already make a giant mess of it. As soon as you get any advanced feature, people will abuse it -- colossal generic functions that take 5 interface{} arguments (but only ever operate on strings), one-off interfaces that have 35 methods, calling out to cgo just because they can, and giant tangles of goroutines, mutexes, semaphores, and sync.Pools all mixed together into one big ball of sadness. But, while everyone has the ability to create such a disaster area, some opt out and use the tool correctly -- making the advanced language features an asset instead of a liability. I don't think generics will change this; when used sparingly and at the right time for the right reason, it will make the code easier to read.
I did a quick look through all my open source projects to see where I have accepted or returned an interface{} in my own APIs, which is a strong signal that I'm looking for generics, or am using a library that wants generics.
One case is interacting with Kubernetes. I have two applications where I set up a reflector like `cache.NewReflector(lw, &v1.Node{}, store, resync)`, to keep a cache up to date; the implementation of "store" takes interface{} for all the arguments (Add, Delete, etc.), even though it only ever operates on a v1.Node. Generics will let me ensure at compile time that I only have to worry about v1.Node objects. Right now, that's handled with runtime assertions in the reflector itself, and in every implementation of the cache.Store. Generics clean this up.
Another case that comes up is processing random JSON objects from the Internet with no defined schema. Those end up as map[string]interface{}, and that won't change.
The last case is unmarshaling functions. I see some (in a JWT validation library) that are of the form `func Unmarshal(string) interface{}`. I don't really know what's going on there, and I don't know if generics will help. (Similarly, for the common case of unmarshaling JSON, I'm not sure generics can improve the `err := json.Unmarshal(bytes, &result)` API. I will have to look into it.
The reason that people find Go to be so much more readable than anything else is because there's often only one way to do the thing you want. The entire language spec is like 2 pages long, and the standard library is relatively thin - generally there are not cases of two libraries that can be used to accomplish the same goal.
This has the general effect of making every piece of code familiar, because every piece of code is forced to use the same ideas to solve adjacent problems.
The foil to this is javascript, where you've got a bunch of different ways to set up functions and promises and async and threading and communications and error handling, etc. Javascript is a very flexible and high level language, but that also means everyone solves problems in their own unique way.
Even I know (not really being a heavy C++ user) that C++ doesn't have generics, it has templates, which is a much more powerful concept that's often overused.
Generics in C++ really damage the readability of the code sometimes, maybe the go devs have found a better way.
The culture might help. I think generics in Java are not overused -- partly because they are not so powerful and partly because Java, similar to Go, did not have generics for a long time.
C++ also went a long time without generics, and even when support started to appear it was a separate code generation step, requiring even more time before we saw first-class compiler support.
If you're really concerned about "clever developers", maybe you ought to ask for the removal of reflect and ast, because they've both been used to be way too clever about solving the same issue.
Generics introduce complexity. That’s pretty undeniable. There are also cases where generics provide much better solutions to problems. That is also undeniable.
As someone who’s working in a Go codebase at work, I’m happy they added generics, especially in the way they did. It’s a pretty minimal subset of generic functionality. I will apply it in certain cases, mostly to reusable code. I think it’s a big win overall though, without introducing too much complexity to the language.
As an outsider planning to eventually learn Go, I have two questions:
1. what's "Go tip"?
2. does this allow us to approximate when it could make it to one of Go's stable releases? I guesstimate it's something that would land not sooner than within a year, right?
On the other side, there are cases, even if they are not very frequent, where generics do help a lot. Just the new slices package allone almost justifies the addition of generics. Furthermore, the proposal looks very much Go-like. As a consequence, I am quite looking forward to try them out and used responsibly[1], they can be a great addition to the Go universe.
1: I think the situation is somewhat similar to Lisp macros. Normally, a codebase rarely requires macros and readability is better, if you avoid creating too many macros. But occasionally there are situations, where using a macro tremendeously increases code quality. Both implementation and readability-wise. There macros should be used and it is great to have them available.
Go is one of the hardest languages to learn. First of all, some concepts in it are very different from "mainstream" languages, and it takes a while to get used to them.
Simple things that exist in almost every other ecosystem can be absent in Go. Want to run setup code before your test suite? You on your own, buddy. And, oh yeah, 2/3 of your code will be `if err` statements, because exceptions are passé.
I learned it by seeking out good Go codebases, which are incredibly rare. Hashi's Terraform comes to mind.
Infamously, the early Kubernetes code was a nightmare because it lifted and shifted Java idioms and that was at the company that invented the Language.
Or at Uber, where they passed on Go's native goroutines and channels in favor of homegrown concurrency, for SOME reason: https://eng.uber.com/go-geofence-highest-query-per-second-se...
All this to show that Go is not a simple language to do well, so let's dispense with that myth.
It has its uses, but having done it, I would never recommend Go for a greenfield project in my place of work - there are very few rules that come with it, and it requires tons of coordination and discipline among a team. And if you have to work with 2 or 3 other people who have strong opinions on how to do things in Go, watch out.
But you can get a pretty good basic Go intro in a few days and be pretty productive after that. It isn't that different from most languages and has a rather small core. Of course, it helps if you have Scheme experience, to understand all the power of high order functions etc.
The first is a purely theoretical exercise, the second a applied one that involves not only the language but also its ecosystem (implementation(s), library of functions and tooling)
https://go2goplay.golang.org/p/krvTH1_7lwX
Wow, interesting. I'm in Japan.
BTW, the readability is really not good as Go 1.
Option types are pointless if you don't have exhaustive pattern matching to ensure correctness.
That would rather miss the point as you'd be converting the type-safe result to an unsafe version?
Go doesn't have pattern matching or any "structural" construct which would allow performing this in a single step, so the alternative would be to use HoFs and while Go has them they're quite verbose e.g.
which is… less than great.An safe other option would be a method mapping to a slice of 0..1 element and you'd use a `for range` as an `if` but that seems way to clever, similar to Scala's comprehensions over everything which I rather dislike.
Also sadly the current proposal has no facilities for methods generic in their arguments independently from the subject, so no `Map` method.
> Generic types can have methods. The receiver type of a method must declare the same number of type parameters as are declared in the receiver type's definition. They are declared without any constraint.
> The type parameters listed in a method declaration need not have the same names as the type parameters in the type declaration. In particular, if they are not used by the method, they can be _.Deleted Comment
https://github.com/golang/go/issues/19412
As for generics, Go’s lack of function overloading and arg default values is really interesting. It ensures that a function is always easily found as it’s the only thing in the module with that name. I’ll be curious to see if generics are easier to follow without function overloading. It will still be only in one place, where as in C++ you could have hundreds of functions with the same name across many libraries and you just have to hope your ide knows which to step into.
There are already a number of langages with generics and without overloading (or defaults). Haskell, ocaml, rust, …
Very skeptical, but the go devs have given me plenty of pleasant surprises before, maybe we get another one here.
I did a quick look through all my open source projects to see where I have accepted or returned an interface{} in my own APIs, which is a strong signal that I'm looking for generics, or am using a library that wants generics.
One case is interacting with Kubernetes. I have two applications where I set up a reflector like `cache.NewReflector(lw, &v1.Node{}, store, resync)`, to keep a cache up to date; the implementation of "store" takes interface{} for all the arguments (Add, Delete, etc.), even though it only ever operates on a v1.Node. Generics will let me ensure at compile time that I only have to worry about v1.Node objects. Right now, that's handled with runtime assertions in the reflector itself, and in every implementation of the cache.Store. Generics clean this up.
Another case that comes up is processing random JSON objects from the Internet with no defined schema. Those end up as map[string]interface{}, and that won't change.
The last case is unmarshaling functions. I see some (in a JWT validation library) that are of the form `func Unmarshal(string) interface{}`. I don't really know what's going on there, and I don't know if generics will help. (Similarly, for the common case of unmarshaling JSON, I'm not sure generics can improve the `err := json.Unmarshal(bytes, &result)` API. I will have to look into it.
That's about it.
Imo Golang buried that theory. I’ve read a lot of Golang code and it’s always been the clearest and most readable code I’ve read.
This has the general effect of making every piece of code familiar, because every piece of code is forced to use the same ideas to solve adjacent problems.
The foil to this is javascript, where you've got a bunch of different ways to set up functions and promises and async and threading and communications and error handling, etc. Javascript is a very flexible and high level language, but that also means everyone solves problems in their own unique way.
So… you know wrong?
Templates are a form of generics. What templates are not is an instance of parametric polymorphism.
The culture might help. I think generics in Java are not overused -- partly because they are not so powerful and partly because Java, similar to Go, did not have generics for a long time.
Powerful, though.
As someone who’s working in a Go codebase at work, I’m happy they added generics, especially in the way they did. It’s a pretty minimal subset of generic functionality. I will apply it in certain cases, mostly to reusable code. I think it’s a big win overall though, without introducing too much complexity to the language.
https://go.dev/blog/generics-proposal
Golang generics proposal has been accepted - https://news.ycombinator.com/item?id=26093778 - Feb 2021 (168 comments)
Go generics proposal moves to “likely accept” - https://news.ycombinator.com/item?id=26018649 - Feb 2021 (92 comments)
A Proposal for Adding Generics to Go - https://news.ycombinator.com/item?id=25750582 - Jan 2021 (270 comments)
The Next Step for Generics - https://news.ycombinator.com/item?id=23543131 - June 2020 (664 comments)
Generics in Go with Ian Lance Taylor (2019) - https://news.ycombinator.com/item?id=22361089 - Feb 2020 (98 comments)
Why Generics? - https://news.ycombinator.com/item?id=20576845 - July 2019 (254 comments)
Go's updated generic proposal (Contracts) - https://news.ycombinator.com/item?id=20541079 - July 2019 (61 comments)
https://go.googlesource.com/proposal/+/refs/heads/master/des...
1. what's "Go tip"?
2. does this allow us to approximate when it could make it to one of Go's stable releases? I guesstimate it's something that would land not sooner than within a year, right?
The plan is to have them available as a preview feature in the next stable release, which is scheduled in about 6 months time.