Is it too late for Go's generics?

I have been using Go since 4 years and I got really good benefits of using it but generics is something really missing so I decided to give Rust a try. And after trying Rust, I realized the power of generics, traits and other concepts in Rust so I am wondering is Go going to survive such long lack of generics? And proper error handling?

I’m a Golang newbie, just my two cents.

Community opinions weigh in the Go core team’s decision to introduce generics. But adding such a big change to the codebase takes considerable effort.

The Golang community are a bunch of developers who are eager to learn and explore. I think it won’t take long for them to adopt generics.

Go was announced in 2009 and version 1.0 was released in 2012. There were plenty of other programming languages that had generics, but the designers of Go didn’t include them in Go. The language continued to grow in popularity in spite of not having generics. Go’s other strengths have made up for it.

For example, the sort package. If I designed the API to Sort, I might have come up with a function like this’

func Slice(slice interface{}, cmp func(a, b interface{}) int)

So that you could use it like this:

ints := []int{1, 5, 2, 4, 3}
sort.Slice(ints, func(a, b interface{}) int { return b.(int) - a.(int) })

Or perhaps the slice parameter is a []interface{}, or perhaps the cmp parameter is an interface{} and called with the reflect package, but you get the picture. I would have thought that’s the best I could do without generics.

What’s really cool to me about the sort package is that the need for generics almost goes away completely. The two parameters to sort.Interface.Less aren’t values, they’re indexes into whatever the collection is, which are always ints. It could be a slice of anything, or it could be some user-defined data structure. Part of the fun of using Go is thinking about making algorithms work well without generics. It’s not just about making the best of a language without generics. Ironically, I think that not having generics leads to thinking about problems differently so that the need for them goes away, resulting in more generalized code.

I don’t know what you mean about “proper error handling.” Go’s error handling is different than exception handling in other programming languages, but it’s still powerful. You’re not supposed to ignore errors in Go. Either the error is unrecoverable and the program should panic with the expectation of crashing, or, if the error is recoverable, it should be returned as an error so the caller can determine a course of action.

4 Likes

I mean shorter, neater, like ? in Rust. Instead of always writing:

if err != nil {
  return err
}

It would be much nicer to have some easy way to achieve this.

And for generics coming so slow to the language, I think the main reason was a resistance of some authors. I think that opinion of the community should drive every open source project including Go, not authors or some “important” (and usually corporate) people.

There was some thought about generics in the beginning but was dropped due to the “after effect” should generic be introduced. Folks tends to go overly creative with generics. This broke 3 of the Go’s values:

  1. easy to use
  2. easy to learn
  3. strict static type checking (magic avoidance)

Hence, the decision was not to take generic in early on and introduce a new concept known as interface to solve some generic needs without breaking Go’s values.

The team is proposing to introduce generics in Go 2. You can join the discussion inside these posts:

  1. https://blog.golang.org/generics-proposal
  2. https://blog.golang.org/generics-next-step

The strict errors checking is adopted from defensive programming practice in critical systems like Linux kernel. The concept is to keep your Go codes as stable and critical as writing a kernel driver, yet removing the crazy high learning curve of creating one.

There are so many ways to reduce the error checking (e.g. package decoupling with vertical approach). :upside_down_face:


My opinion ahead

Given the fact that Go actually solve some severe pain points in software ecosystem such as:

  1. Managing dependencies for final output binary (e.g. AppImage like output)
  2. Compilation approach (codes friendly to human; output binary friendly to CPU)
  3. Standardizes codes for fast learning (easy to read, learn, reference, and peer review)
  4. Customer distribution (it’s so easy to package and distribute 1 binary app)
  5. Friendliness to current modern platforms (looking at Git, Gitlab, Gittea, and Github)

Go would not die off due to the absent of generics by the fact that something as large and critical as Linux kernel did not use generics. I strongly believe Rob Pike and his founding team did consider that into their thought process and have their strong reasons not to include in. For me, generic is optional (good to have). No harm introducing if it does not sacrifice Go’s existing values and performances.

That’s why Go branded themselves “opinionated” language in the first place.

6 Likes

Man, you are whining about 2 things, ironically I love in Go: strong type system and explicit error handling. Go will survive even without generics, as there are still many people like @skillian and myself. Good look with Rust, I like it as well.

1 Like

What does the language gain by adding Generics? I mean, is it an essential, or is it a convenience?
My background is Java, and that used to be a nice clean O-O language. Now it’s become cluttered with lots of convenience features, in an attempt to match other languages with those features.

I was once asked to do a programming challenge for an interview. At the code review, one of the interviewers asked me why I didn’t use more Java 8 features. What I should have said at the time was, ‘because I didn’t need to’ :slight_smile:

My point is that just because a language feature is convenient, doesn’t mean it’s essential, and can add clutter to the language. After all, most IDEs these days can insert code snippets and literally write the code for you!
I would not like to see Go become cluttered with lots of syntactic baggage. I like its refreshingly simple approach.

2 Likes

Yes, clean syntax is nice but once you get into code repetitions because of lack of generics, it becomes cluttered. It is also cluttered because of error handling, every now and then you see:

if err != nil {
  return err
}

I wrote lot of Go code already and these are really bad sides of using Go. The third thing is maybe lack of enum type, constants are in many cases not strict enough.

Yeah good point about the error handling. Must say I was surprised that there’s no exception handling mechanism in the language, which IMO is a pretty good way of catching error conditions.

It would be nice to have ? as in Rust, but in Rust this is compatible with Result type and in Go I don’t know how it can be implemented because calling function may have different return value than the main function. Maybe just return zero values and error, but I don’t know, people are not discussing this anymore, we all gave up on this :grinning:

Ok, apologies if I’m flogging a dead horse :laughing:

There is… but was frown upon. See: https://blog.golang.org/defer-panic-and-recover and json package as example if I’m not mistaken.

You can use in your implementation, but I believe somewhere in the journey of continuous improvement, you will start asking myself why not just check the error directly.

Nahh… it’s better to check the error object pointer is nil. I mean, 1 output is enough per function call check, now 2?!

Keep in mind that you don’t necessarily need to strictly check every single error. Algorithms that guarantee one-sided outcome (e.g. you already hard-coded certain parameters) don’t have to re-create the error object just for the sake of it.

Alternatively, you can use panic whenever you want your developers to fix it at compilation/testing stage. I seen creative Go developers did very well with it. That will significantly reduces the error checking to those dynamics/runtime needs (where panic makes no sense).

What do you mean? Go is VERY VERY strict with function input/output with exception to abusing interface feature for duck typing.


Actually, if I’m looking for those features you mentioned, I would indeed use Rust for the task and leave Go as it is. There isn’t any value to converge all of features into a very bulky swiss knife language like that long-aged very obsessed Python. Don’t worry, Go community is not religious. Just use the right tool for the right thing. :grin:

So here’s a case: former Python2+3 here. I eventually gave up Python in favor of “disciplined POSIX/BASH” script working alongside Go. Some notable reasons was:

  1. The requirement to install that bulky Python standard engine in order to use a very simple program. (POSIX/BASH replaced this)
  2. To convert into binary, it involves quite some efforts to write the Makefile. (Go replaced this)

The point is, if we converge everything into 1 big swiss knife again, ultimately, at some point, we will need to work our way splitting them up.

Hey guys, Some good news for all of you :grin: :upside_down_face: