top | item 14763111

Toward Go 2

746 points| dmit | 8 years ago |blog.golang.org

640 comments

order
[+] munificent|8 years ago|reply

    > I can't answer a design question like whether to support 
    > generic methods, which is to say methods that are
    > parameterized separately from the receiver.
I work on the Dart language. Dart was initially designed with generic classes but not generic methods. Even at the time, some people on the team felt Dart should have had both.

We proceeded that way for several years. It was annoying, but tolerable because of Dart's optional type system -- you can sneak around the type checker really easily anyway, so in most cases you can just use "dynamic" instead of a generic method and get your code to run. Of course, it won't be type safe, but it will at least mostly do what you want.

When we later moved to a sound static type system, generic methods were a key part of that. Even though end users don't define their own generic methods very often, they use them all the time. Critical common core library methods like Iterable.map() are generic methods and need to be in order to be safely, precisely typed.

This is partially because functional-styled code is fairly idiomatic on Dart. You see lots of higher-order methods for things like manipulating sequences. Go has lambdas, but stylistically tends to be more imperative, so I'm not sure if they'll feel the same pressure.

I do think if you add generic types without generic methods, you will run into their lack. Methods are how you abstract over and reuse behavior. If you have generic methods without generic classes, you lose the ability to abstract over operations that happen to use generic classes.

A simple example is a constructor function. If you define a generic class that needs some kind of initialization (discouraged in Go, but it still happens), you really need that constructor to be generic too.

[+] dgacmu|8 years ago|reply
I should send this to rsc, but it's fairly easy to find examples where the lack of generics caused an opportunity cost.

(1) I started porting our high-performance, concurrent cuckoo hashing code to Go about 4 years ago. I quit. You can probably guess why from the comments at the top of the file about boxing things with interface{}. It just got slow and gross, to the point where libcuckoo-go was slower and more bloated than the integrated map type, just because of all the boxing: https://github.com/efficient/go-cuckoo/blob/master/cuckoo.go

(my research group created libcuckoo.)

Go 1.9 offers a native concurrent map type, four years after we looked at getting libcuckoo on go -- because fundamental containers like this really benefit from being type-safe and fast.

(2) I chose to very tightly restrict the initial set of operations we initially accepted into the TensorFlow Go API because there was no non-gross way that I could see to manipulate Tensor types without adding the syntactic equivalent of the bigint library, where everything was Tensor.This(a, b), and Tensor.That(z, q). https://github.com/tensorflow/tensorflow/pull/1237 and https://github.com/tensorflow/tensorflow/pull/1771

I love go, but the lack of generics simply causes me to look elsewhere for certain large classes of development and research. We need them.

[+] fusiongyro|8 years ago|reply
The paragraph I was looking for is this:

> For example, I've been examining generics recently, but I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve. As a result, I can't answer a design question like whether to support generic methods, which is to say methods that are parameterized separately from the receiver. If we had a large set of real-world use cases, we could begin to answer a question like this by examining the significant ones.

This is a much more nuanced position than the Go team has expressed in the past, which amounted to "fuck generics," but it puts the onus on the community to come up with a set of scenarios where generics could solve significant issues. I wonder if Go's historical antipathy towards this feature has driven away most of the people who would want it, or if there is still enough latent desire for generics that serious Go users will be able to produce the necessary mountain of real-world use cases to get something going here.

[+] crawshaw|8 years ago|reply
Several members of the Go team have invested significant effort in studying generics and designing proposals, since before Go 1.0. For example, Ian Lance Taylor published several of his previous efforts, which had shortcomings he was dissatisfied with.

I believe your impression of the Go team's position has been corrupted (likely unintentionally) by intermediaries.

[+] bad_user|8 years ago|reply
Java`s generics have had issues due to use site variance, plus the language isn't expressive enough, leading its users into a corner where they start wishing for reified generics (although arguably it's a case of missing the forest from the trees).

But even so, even with all the shortcomings, once Java 5 was released people migrated to usage of generics, even if generics in Java are totally optional by design.

My guess to why that happens is that the extra type safety and expressivity is definitely worth it in a language and without generics that type system ends up staying in your way. I personally can tolerate many things, but not a language without generics.

You might as well use a dynamic language. Not Python of course, but something like Erlang would definitely fit the bill for Google's notion of "systems programming".

The Go designers are right to not want to introduce generics though, because if you don't plan for generics from the get go, you inevitably end up with a broken implementation due to backwards compatibility concerns, just like Java before it.

But just like Java before it, Go will have half-assed generics. It's inevitable.

Personally I'm sad because Google had an opportunity to introduce a better language, given their marketing muscle. New mainstream languages are in fact a rare event. They had an opportunity here to really improve the status quo. And we got Go, yay!

[+] didibus|8 years ago|reply
I get that everyone would love to have a functional language that's eager by default with optional lazy constructs, great polymorphism, statically typed with inference, generics, great concurrency story, an efficient GC, that compiles quickly to self contained binaries with simple and effective tooling which takes only seconds to setup while giving you perfomance that equals java and can rival C, with a low memory footprint.

But, I don't know of one, and maybe that's because the Go team is right, some tradeoffs need to be made, and they did, and so Go is what it is. You can't add all the other great features you want and eat the Go cake too.

Disclaimer: I'm no language design expert. Just thinking this from the fact that I've yet to hear of such a language.

[+] EddieRingle|8 years ago|reply

    > To minimize disruption, each change will require
    > careful thought, planning, and tooling, which in
    > turn limits the number of changes we can make.
    > Maybe we can do two or three, certainly not more than five.

    > ... I'm focusing today on possible major changes,
    > such as additional support for error handling, or
    > introducing immutable or read-only values, or adding
    > some form of generics, or other important topics
    > not yet suggested. We can do only a few of those
    > major changes. We will have to choose carefully.
This makes very little sense to me. If you _finally_ have the opportunity to break backwards-compatibility, just do it. Especially if, as he mentions earlier, they want to build tools to ease the transition from 1 to 2.

    > Once all the backwards-compatible work is done,
    > say in Go 1.20, then we can make the backwards-
    > incompatible changes in Go 2.0. If there turn out
    > to be no backwards-incompatible changes, maybe we
    > just declare that Go 1.20 is Go 2.0. Either way,
    > at that point we will transition from working on
    > the Go 1.X release sequence to working on the
    > Go 2.X sequence, perhaps with an extended support
    > window for the final Go 1.X release.
If there aren't any backwards-incompatible changes, why call it Go 2? Why confuse anyone?

---

Additionally, I'm of the opinion that more projects should adopt faster release cycles. The Linux kernel has a new release roughly every ~7-8 weeks. GitLab releases monthly. This allows a tight, quick iterate-and-feedback loop.

Set a timetable, and cut a release with whatever is ready at the time. If there are concerns of stability, you could do separate LTS releases. Two releases per year is far too short, I feel. Besides, isn't the whole idea of Go to go fast?

[+] jimjimjim|8 years ago|reply
Here be Opinions:

I hate generics. also, I hate exceptions.

Too many people are wanting "magic" in their software. All some people want is to write the "Happy Path" through their code to get some Glory.

If it's your pet project to control your toilet with tweets then that's fine. But if it's for a program that will run 24/7 without human intervention then the code had better be plain, filled with the Unhappy Paths and boring.

Better one hour writing "if err" than two hours looking at logs at ohshit.30am.

[+] baq|8 years ago|reply
there's nothing magic about generics. every time you make a channel or a map in go, you're using a generic function even if go people don't want you to call it that.

there's nothing magic about exceptions, too, it's that it's harder than necessary to use them correctly and that's why it's not as big of a deal to not have them in go - as evidenced by this thread.

[+] ovao|8 years ago|reply
In Go, the magic right now is actually in special-cased types like map. Generics actually have the potential to reduce the amount of magic as it exists currently.

The design can go badly wrong, of course, but it can also go wonderfully right. Generics are a very important feature to consider for the language.

I have no opinion on exceptions with regard to Go specifically. I think they serve a good purpose in other languages but are often misused.

[+] abiox|8 years ago|reply
in a sense, generics just let you provide parameters to your types, just like you give parameters to functions. it's not all that magical.
[+] di4na|8 years ago|reply
As erlang shows, quite the contrary. If you want your code to stay up and running you should concentrate on the happy path, bulkhead and let it crash.

I advice to read about Human Factors and Complex Systems engineering. You will be surprised.

[+] fredmorcos|8 years ago|reply
> But if it's for a program that will run 24/7 without human intervention then the code had better be plain, filled with the Unhappy Paths and boring.

You mean like memory and resource management code? Oh wait.. you use a garbage collected language. lol

[+] mmargerum|8 years ago|reply
So much this. Been doing this for 25 years and I loathe magic like Exceptions. I consider Go's explicit error handling a plus. Any editor would let you code ife to generate the error scaffold.

I don't hate generics, but I don't require them either. If the Go guys can make them work well and fit into the language i'd be fine with it, but I don't want them to feel pressured into throwing something out there for the language purists. I doubt they feel pressured. They've been around the block and have as good a sense as any group i've ever seen for what to include in the language.

Go is not the language to use if you want to write clever code, but it's great when you write code for businesses that must run 24x7.

[+] Analemma_|8 years ago|reply
> For example, I've been examining generics recently, but I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve.

This is sampling bias at work. The people who need generics have long since given up on Go and no longer even bother participating in Go-related discussions, because they've believe it will never happen. Meanwhile, if you're still using Go, you must have use cases where the lack of generics is not a problem and the existing language features are good enough. Sampling Go users to try and find compelling use cases for adding generics is not going to yield any useful data almost by definition.

[+] loup-vaillant|8 years ago|reply
> For example, I've been examining generics recently, but I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve. […] If we had a large set of real-world use cases, we could begin to answer a question like this by examining the significant ones.

Not implementing generics, then suggesting that it would be nice to have examples of generics being used in the wild… You had it coming, obviously.

Now what's the next step, refusing to implement generics because nobody uses it?

> Every major potential change to Go should be motivated by one or more experience reports documenting how people use Go today and why that's not working well enough.

My goodness, it looks like that is the next step. Go users have put up with the absence of generics, so they're not likely to complain too loudly at this point (besides, I hear the empty interface escape hatch, while not very safe, does work). More exacting developers have probably dismissed Go from the outset, so the won't be able to provide those experience reports.

[+] why-el|8 years ago|reply
> Not implementing generics, then suggesting that it would be nice to have examples of generics being used in the wild… You had it coming, obviously.

I think you misunderstood. Clearly he meant to ask for examples from the real world that lack generics, but shows how adding them would improve the system.

[+] zackmorris|8 years ago|reply
Go doesn't have const structs, maps or other objects:

https://stackoverflow.com/questions/43368604/constant-struct...

https://stackoverflow.com/questions/18342195/how-to-declare-...

This is a remarkable oversight which makes it impossible to write purely-functional code with Go. We also see this same problem in most other imperative languages, with organizations going to great lengths to emulate const data:

https://facebook.github.io/immutable-js/

Const-ness in the spirit of languages like Clojure would seem to be a relatively straightforward feature to add, so I don't really understand the philosophy of leaving it out. Hopefully someone here knows and can enlighten us!

[+] secure|8 years ago|reply
There doesn’t need to be a philosophy behind leaving it out. Go was started by selecting only features which were deemed necessary. I think it’s fair to assume the creators of Go didn’t design it for writing purely-functional code, so that’s why it’s not in (yet?)
[+] zemo|8 years ago|reply
it's almost like writing purely-functional code is not the goal of Go.
[+] akavel|8 years ago|reply
I believe part of the reason was also some experience with C++, in which you sometimes have to "unconst" some fields of your const classes (the mutable keyword). This is a really ugly and nonintuitive design, so I assume they'd rather take extra care to make sure they don't have to repeat it. Even if it means no const at all.
[+] AnimalMuppet|8 years ago|reply
There are many comments griping about generics. There are many comments griping about the Go team daring to even ask what problems the lack of generics cause.

But take a look at this article about the design goals of Go: https://talks.golang.org/2012/splash.article Look especially at section 4, "Pain Points". That is what Go is trying to solve. So what the Go team is asking for, I suspect, is concrete ways that the lack of generics hinders Go from solving those problems.

You say those aren't your problems? That's fine. You're free to use Go for your problems, but you aren't their target audience. Feel free to use another language that is more to your liking.

Note well: I'm not on the Go team, and I don't speak for them. This is my impression of what's going on - that there's a disconnect in what they're asking for and what the comments here are supplying.

(And by the way, for those here who say - or imply - that the Go team is ignorant of other languages and techniques, note in section 7 the casual way they say "oh, yeah, this technique has been used since the 1970s, Modula 2 and Ada used it, so don't think we're so brilliant to have come up with this one". These people know their stuff, they know their history, they know more languages than you think they do. They probably know more languages than you do - even pjmlp. Stop assuming they're ignorant of how generics are done in other languages. Seriously. Just stop it.)

[+] lemoncucumber|8 years ago|reply
As much as I want them to fix the big things like lack of generics, I hope they fix some of the little things that the compiler doesn't catch but could/should. One that comes to mind is how easy it is to accidentally write:

  for foo := range(bar)
Instead of:

  for _, foo := range(bar)
When you just want to iterate over the contents of a slice and don't care about the indices. Failing to unpack both the index and the value should be a compile error.
[+] mmargerum|8 years ago|reply
I've got caught by this more than once. Again, implicit behavior sucks so I suggest they get rid of the first form.
[+] mappu|8 years ago|reply
If `bar` is a slice then the short syntax isn't that useful (although it's shorter than the three-clause for loop equivalent).

But if `bar` is a map or a channel, then that short syntax is very handy.

For comparison's sake, you don't see many PHP users complaining about the difference between `foreach($bar as $foo)` and `foreach($bar as $_ => $foo)`.

[+] tschellenbach|8 years ago|reply
The beauty of Go is that you get developer productivity pretty close to Ruby/Python levels with performance that is similar to Java/C++

Improvements to package management is probably the highest item on my wishlist for Go 2.

[+] the_duke|8 years ago|reply
There is so much boilerplate you have to write that productivity drops considerably, both because you have to re-re-re-re-implement things (or use code generation) and because you need to scan lot's of redundant code before making sense of it.

The alternative is often to just use interface{}, which hurts performance and type safety.

[+] owaislone|8 years ago|reply
> Improvements to package management is probably the highest item on my wishlist for Go 2.

The work is in progress and will most likely be available for general purpose use way before Go2.

Check it out: https://github.com/golang/dep

[+] Walkman|8 years ago|reply
The productivity level is nowhere near to Python's yet. You should try Go for a couple of weeks and see that still soooo much missing from Go compared to Python.
[+] michaelcampbell|8 years ago|reply
> The beauty of Go is that you get developer productivity pretty close to Ruby/Python levels ...

I'm curious as to what metric you use for "developer productivity", and the values of said metric you can cite for the 3 languages you list.

[+] zbobet2012|8 years ago|reply
That's going to happen before go 2. Go 1.9 / 1.10 time frame.
[+] Xeoncross|8 years ago|reply
Generics have never stopped me from building in Go... But without them I often do my prototyping in python, javascript, or php.

Working with batch processing I'm often changing my maps to lists or hashes multiple times during discovery. Go makes me rewrite all my code each time I change the variable type.

[+] notheguyouthink|8 years ago|reply
It's weird, I see these complaints so often and I just.. don't.. get it. I'm not sure what I do differently, but I'm just so used to Go's method of non-generic that I don't run into frustration at all.

The only time I even notice it is if I have to write a method like `AcceptInt(), AcceptString(), AcceptBool()` and etc.

I enjoy generics in Rust, I'm just not sure what I'm doing differently in Go that causes me to not miss them.

[+] alexandernst|8 years ago|reply
How about fixing all the GOPATH crap?
[+] oelmekki|8 years ago|reply
As a ruby and go dev, I'm a bit sad to see backward-compatibility going. Thinking I could write code with minimum dependencies and that would just work as is years later was really refreshing compared to the high level of maintenance needed in a ruby app.

But well, I trust the core team to make the best choices.

[+] vbezhenar|8 years ago|reply
I like Go concept: very simple and minimalistic language, yet usable enough for many projects, even at cost of some repetition. Generics are not a concern for me. But error handling is the thing I don't like at all. I think that exceptions are best construct for error handling: they are not invasive and if you didn't handle error, it won't die silently, you have to be explicit about that. In my programs there's very little error handling, usually some generic handling at layer boundaries (unhandled exception leads to transaction rollback; unhandled exception returns as HTTP 500, etc) and very few cases when I want to handle it differently. And this produces correct and reliable program with very little effort. Now with Go I must handle every error. If I'm lazy, I'm handling it with `if err != nil { return err; }`, but this style doesn't preserve stack trace and it might be hard to understand what's going on. If I want to wrap original error, standard library don't even have this pattern, I have to roll my own wrapper or use 3-rd library for such a core concept.

What I'd like is some kind of automatic error propagation, so any unhandled error will return from function wrapped with some special class with enough information to find out what happened.

[+] insulanian|8 years ago|reply
> For example, I've been examining generics recently, but I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve.

Collections?

[+] nebabyte|8 years ago|reply
But I always heard never to use Go 2! :P
[+] cdnsteve|8 years ago|reply
"We estimate that there are at least half a million Go developers worldwide, which means there are millions of Go source files and at least a billion of lines of Go code"
[+] ovao|8 years ago|reply
Perhaps fewer than a billion lines of Go code if there were generics.