NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
Golang proposal: container/: generic collection types (github.com)
DarkNova6 22 hours ago [-]
Step by step, Go is now learning the hard lessons every other language has learned over the last 20 years. The fact that despite their best efforts, their propositions look like everone else is a surprisingly refreshing affirmation of status quo.
somekyle2 21 hours ago [-]
I respect "we're going to try not to add features until we have to and have a plan that we like" as an approach to a practical language, vs "we're going to plan to support everything normal modern languages have". It isn't the best approach to language design in theory, but they did try to build a language that isn't impossible to change, and to be fair the mix of language features they chose didn't have any good more successful examples to borrow from, so waiting for enough practical experience to make the relevant trade-offs on practical grounds isn't the bare naivety that some people seem to take it as.
DarkNova6 20 hours ago [-]
I totally get that. Java is my favorite language for exactly that reason. They are a deliberate "late mover language" and adopt what other languages have proven right.

But looking at how adamant Go used to be on the whole "No Generics" stance and the path and the troubles they are having... it all seemes so preventable?

farfatched 19 hours ago [-]
I think it was.

Go without generics was ok. I say that as a fan of generics in other languages.

There is room for languages with simpler feature sets.

It takes a strong leader (and the good and bad that comes with that) to continue to deny features. Go had that. Does it still? (I genuinely don't know.)

I'm not sure what Go's value proposition is now.

Developers can't pick it up in a week, as it used to be. Maybe that's okay too, since Go already has critical mass.

ako 18 hours ago [-]
Go value proposition for me, when developing with Claude code: 1) fast compilation times, faster iterations, 2) user friendly to install, one single binary per platform, 3) feels safer than JavaScript/typescript, which have too many npm vulnerabilities. Go comes with more functionality included, less need to use 3rd party libraries.
farfatched 17 hours ago [-]
That's fair. In addition, I'd add the great compatibility guarantees, and a community that makes easy-to-learn libraries.
hwc 10 hours ago [-]
> Developers can't pick it up in a week...

I don't think any of the new additions to the library have seriously made the learning curve more difficult. I suspect that most projects don't use templates at all.

There have always been parts of the standard library I'm not familiar with. when I read code that uses it, I just go read the documentation. Now the standard library is just larger.

kamma4434 15 hours ago [-]
> Go without generics was ok. I say that as a fan of generics in other languages.

Well kinda. I found it very annoying every time you want to print a sorted map which keys are strings that you could not abstract the operation. It felt like paying a stupidity tax. (And I quite like go. It’s the only language where write once run everywhere actually works. Cross compiling for all targets is as easy as creating a local binary)

LVB 16 hours ago [-]
I don’t feel like the learning curve has shifted dramatically for mainstream development. Besides generics—which tend to not show up that often in app code even now—I can’t think of any substantial language change since I Iearned it in 2014. (Well, modules, but that’s more tooling.) Where I do see the shock is jumping to def of a std lib function and landing in indecipherable type soup.
shikck200 14 hours ago [-]
Go never was "no generics". It had generics rusted in from the get-go, but never implemented them as it was a complex feature and one that made the compiler slower. Im glad they waited. Compare to PHP, where every feature is bolted on and then you end up supporting it forever.
TZubiri 12 hours ago [-]
A very common trap I find myself falling into is forgetting that there's a difference between the language, and the most common compiler/interpreter implementation.

It's a very practical simplification since 99% of the time, that's what we use. 'It's in the language, we just don't use it' does sound like copeful technicality, until it isn't and it's an actually impactful difference.

win311fwg 19 hours ago [-]
Does it? It was only preventable by not releasing Go, which isn't exactly the greatest of solutions.

As you know from when Go was first broadcast to the world, they hadn't figured out how to make generics fit[1]. It is not like they weren't trying. Ian Lance Taylor is regarded for beginning work on generics before anyone outside of Google had even heard of Go. "In short: not yet"

What was surprising is that after Go was released as an open source project, nobody across the whole wide world ever came up with a workable solution. You can sense the optimism in that original announcement that later turned to "Go might never get generics" dispair. As you'll recall, it finally took convincing Philip Wadler (of Haskell and Java generics fame) to help. Without that lucky break, which almost certainly never would have happened if Go was still some basement project used by nobody, Go probably still wouldn't have generics.

[1] https://youtu.be/rKnDgT73v8s?t=3267

pjmlp 15 hours ago [-]
More like no one on the world was able to change their mind, and then they had to ask help to someone that could already have provided help before Go released 1.0 version.

"They are likely the two most difficult parts of any design for parametric polymorphism. In retrospect, we were biased too much by experience with C++ without concepts and Java generics. We would have been well-served to spend more time with CLU and C++ concepts earlier."

https://go.googlesource.com/proposal/+/master/design/go2draf...

win311fwg 14 hours ago [-]
Quite right. If the Go team somehow magically had the right technical background Go would have had generics earlier, but they didn't and weren't going to magically get it, so we're back to the only preventable way was to not release it at all.

But one would think that of the billions of people in the world that someone outside of the Go team would have had that familiarity to quickly change that, but no proposals came from that direction for over a decade and a lot of begging. I suppose those who had the chops were too busy constantly posting on HN about how Go doesn't have generics to lend their expertise. Priorities.

It's great to reflect back in hindsight about where you failed, but it's always easy to see where you failed after someone else finally shows you the way. The simple fact that the Go team did not have the technical capability to be able to add generics at the time remains. Being able to create a relatively popular programming language (or set of popular programming languages for some of them) certainly does not imply that you are a programming language expert. There may even be an inverse correlation. Those who show to be programming language gods appear most likely to end up creating esoteric languages that end up on the pile of languages that remain unknown and unused.

pjmlp 14 hours ago [-]
Go is basically a mix between Oberon-2 and Limbo, which we all know where they landed on the adoption curve.

Without the adoption success of Docker and Kubernetes adding wind to Go's sails, Go would have landed on the island.

They were not lacking in skills, rather politics, and there is a public talk from Rob Pike where he mentions even the Go 1.18 generics would not have landed if it was for him.

win311fwg 13 hours ago [-]
> Go is basically a mix between Oberon-2 and Limbo, which we all know where they landed on the adoption curve.

Exactly. You might say that Wirth, Mössenböck, and Winterbottom had some programming language chops, bringing some new ideas to the world, which is in line with the observation that those with programming language skills end up creating languages nobody uses. In fairness, Pike was involved in Limbo, but his only claim to fame was pressuring Winterbottom to add garbage collection to Alef, thus Limbo.

> Without the adoption success of Docker and Kubernetes adding wind to Go's sails, Go would have landed on the island.

Fun story, but no. Those projects chose Go because Go had already gained traction and was thought, in that moment in time, that it was going to be the way of the future.

It is true that Docker is often credited as the first major success story, but Hugo, etcd, InfluxDB, etc. were all released around the same time, never mind the long list of projects that never gained popularity. The language was already being widely used by the time Docker showed up. Go didn't need a major success story to get on the radar. It had Google's marketing power behind it, or at least that's why most believe it was able to become popular without having any breakouts to its name.

> They were not lacking in skills, rather politics

These are not separable concepts. Politics are the result of lack of skill.

pjmlp 7 hours ago [-]
Really wearing the team's t-shirt there, Go was barely proven on the language adoption battlefield when Go heads preverted the direction Docker and Kubernetes were going, it wasn't even 1.0.

Lots of languages are full of dead projects that never gained notoriety.

In fact, YouTube downloader which is another "success" only happened, because once again, it was a gopher that forced a RIG, it was working perfectly fine.

win311fwg 6 hours ago [-]
> Really wearing the team's t-shirt there

Ad hominem is a logical fallacy.

> Go was barely proven on the language adoption battlefield when Go heads preverted the direction Docker and Kubernetes were going, it wasn't even 1.0.

Exactly. All these projects chose Go many years before anyone, outside of Docker, had heard of Docker. This idea that Go was some kind of underground language until Docker and Kubernetes arrived at which point everyone jumped on the bandwagon is simply not true. Go was already quite popular by the time Docker was released, as evidenced by a whole lot of other projects that became popular themselves being released at the same time. Those projects wouldn't have been able to have been released when they did if they waited for Docker's success to jump on the Go bandwagon.

> Lots of languages are full of dead projects that never gained notoriety.

No there aren't. Not where the language is on the heap of languages nobody has ever heard of. Oberon-2 and Limbo didn't fail because they never found their "Docker", they failed because nobody used them in the first place.

typical182 6 hours ago [-]
> it finally took convincing Philip Wadler (of Haskell and Java generics fame) to help. Without that lucky break [...] Go probably still wouldn't have generics.

Small correction, I think:

My understanding is the core Go team was already well on its way to doing generics before Philip Wadler became involved, though he and his colleagues were later very helpful.

From Wadler's "Featherweight Go" paper [1] (the first draft of which seems to have been uploaded to arxiv.org circa May 2020):

Recently, the Go team mooted a design to extend Go with generics [Taylor and Griesemer 2019], and Rob Pike wrote Wadler to ask: Would you be interested in helping us get polymorphism right [...]

and:

It took us several tries over many months to formalise it correctly.

Well before that, doing generics was one of the main focuses in the GopherCon keynotes/announcements in 2017 and 2018 by Russ Cox [2].

The August 2018 generics design [3][4] was very detailed, and my recollection is most people in the Go community at that point believed the core Go team was going to make generics happen, even if the team and community were still iterating on the exact design.

Of course, that design improved over time, including thanks to Wadler and crew, but I think it would be overstating things to say that probably nothing would have happened without Wadler.

[1] https://arxiv.org/pdf/2005.11710v1

[2] https://go.dev/blog/go2draft

[3] https://go.googlesource.com/proposal/+/master/design/go2draf...

[4] https://go.googlesource.com/proposal/+/master/design/go2draf...

19 hours ago [-]
vlovich123 21 hours ago [-]
The problem is that when you don’t have a cohesive picture of how things fit from the outside, it becomes really hard to evolve the language in a way that makes sense and doesn’t break existing code. Data storage and languages share this unique property that the past impacts your decisions and what makes is possible in the future in a way pure logic doesn’t struggle with.
Sleaker 20 hours ago [-]
And this is -exactly- one of the reasons they didn't accept or continue with a sane proposal for more ergonomic error handling. I like go, but this was the one thing that I kept feeling like I was wasting so much time dealing with.
win311fwg 14 hours ago [-]
Presumably you are referring to https://github.com/golang/go/discussions/71460?

While the proposed slightly reduced the token count, saving the average typist approximately 1 second of time if they don't have an autocomplete editor that types it for them, it doesn't change anything about the mental model where the real time is actually spent, so is it really sane?

Worse, it is dependent on the error type, but errors are not always of the error type. Not even Go's own standard library consistently returns errors using the error type, never mind all the other crazy things you find in the wild.

That doesn't sound sane at all.

It is true that Go not having any real kind of superpositions or side channels makes stealing popular ideas from other languages impossible (it already has both well-known error handling methods that do not depend on those properties). But a sane proposal would be designed with that in mind.

ndriscoll 9 hours ago [-]
Reducing syntactic noise is about legibility, not writing ease. The error boilerplate as it exists interrupts the actual logic and makes most of your code read as sad paths that might never execute.

Of course if you want something less specific to errors, we already have do-notation as an excellent example to look at. And you can't say that's more complex for users than what they did with iterators.

sethammons 9 hours ago [-]
> The error boilerplate as it exists interrupts the actual logic and makes most of your code read as sad paths that might never execute.

Yes! You have to think through and account for edge cases. "Might not" is the same as "might." Those branches might execute.

I have been on many projects over 25 years of software development. Projects that take error handling seriously tend to be better all around. Happy-path coding is naive.

ndriscoll 8 hours ago [-]
In the overwhelming majority of cases, you want to trivially send the error up the stack to be handled, so you don't want to incur the noise in the middle of your business logic (and indeed doing so obscures the times when error handling is non-trivial!). e.g. Scala handles all error cases with compile time checking (in fact it tends to take error handling much more seriously), but you don't have to write (or read) the trivial case.
kbolino 8 hours ago [-]
> In the overwhelming majority of cases, you want to trivially send the error up the stack to be handled

Maybe so, but for JVM languages, this "trivially" includes a stack trace. Go doesn't offer that for normal errors and there was no clear path to getting it. The need for contextual clues when debugging, and the community and then stdlib settling on error-wrapping as the way to do it, makes "simply return err" not a sane default anymore.

ndriscoll 6 hours ago [-]
That's just pointing out another layer of noise Go introduces. Here again in Scala, you can get stack traces for free with no extra syntax with value-based errors. There are already solutions for doing these things that have been used in anger for many years.

In a language that takes error handling seriously, you have domain types for errors, type checking for exhaustive error handling, and you get info like a stack trace out of the box.

kbolino 5 hours ago [-]
Ignoring the stack trace matter, which is explored in the sibling thread, it seems to me you're really taking issue with two of Go's language design choices that aren't specifically about errors: structural typing and the lack of proper discriminated unions.

There is nothing special about an error in Go, and there is no type hierarchy to anchor them against anyway. An error can be a struct{} carrying no value at all, or simple integer with no way to carry context, etc. Error-wrapping is the solution that has been devised to work within these constraints, but there's no obvious way to compose that with the various ideas around reducing boilerplate. For a point of comparison, Rust's anyhow crate was able to square this circle by adding a blanket trait impl for Context, but Go has no equivalent for that. (Also, Rust's ? operator is implemented using unstable components, allowing the details to evolve even while the feature itself is usable in stable Rust, something which also has no equivalent in Go).

As to the lack of discriminated unions, I agree wholeheartedly. There have been some proposals recently to get them into the language, with various levels of conservatism and cohesion with the rest of the language, but a lot of them are faltering on the "every type must have a well defined zero value" issue (yet another design decision that doesn't necessarily have anything to do with errors).

ndriscoll 5 hours ago [-]
As an aside, the "every type must have a zero value" is another level of insanity akin to pi must be 3: tempting to want it to be true but disastrously wrong. You're basically making known good practice (RAII/make invalid states unrepresentable) impossible, especially when you combine it with the lack of if-expressions. It also breaks parametric reasoning since now a function `() => a` exists.

I had to argue about this years ago with a coding standard pushing to define local variables at the top of functions and zero initialize them in C. Why default to null pointers or worse (invalid ints/structures) when you could make use of uninitialized variables be a compiler error instead!?

kbolino 5 hours ago [-]
Technically, Java has the same rule, it's just that all user-defined types are reference types, and so the zero value for them is always spelled "null". I'm not sure how Scala pretends otherwise, but I have worked with Kotlin, and non-nullable object fields and method arguments are always a bit of a lie, since the underlying JVM machinery permits, and defaults to, null. (Despite the original authors of Go being unfamiliar with Java, they do seem to have settled on a number of the same decisions.)

Personally, I'm fine with discriminated unions always allowing "nil" in Go, since IMO the most sensible way to implement them anyway is as a special case of interfaces. Not everyone feels the same way, though.

9rx 5 hours ago [-]
Every value must have a zero value was congruent with the dynamic languages of the time, which is signifiant as Go was designed to "feel like a dynamic language" that was able to handle production scale (i.e. something that could handle Google-sized loads). There is a good possibility that Go wouldn't have even had a static type system if they had figured out how to make dynamic typing fast.

That may seem out of place in the world you live in, but Go was created in a world where Python, Ruby, and Javascript were the languages all the cool kids were using. Go was intended to be the language for C++ programmers who had to use C++ for performance reasons but wished they could use Python instead.

Insanity, perhaps, but Go was designed to solve a problem for the world it lived in. You don't get to choose your circumstances. For those living in paradise, they can use the languages designed for their world.

win311fwg 6 hours ago [-]
> Go doesn't offer that for normal errors and there was no clear path to getting it.

It does offer that for normal errors if you pass those errors via exceptions. Although you're right that using exceptions for error handling is pretty weird and generally avoided in Go, much to the chagrin of Java developers.

The Upspin experiment, which eventually shaped the error additions that did make it into Go, showed a clear path to getting it in errors themselves, but it also revealed that nobody actually uses them when available. The research found that even with stack traces attached, developers didn't bother looking at them. Thus why that bit didn't make it into Go.

kbolino 5 hours ago [-]
Yes, I don't think stack traces are a silver bullet. They tell you the path taken through the code, but rarely do they tell you why that path was taken. I don't know what Scala stack traces look like specifically, but I've done my fair share of parsing Java stack traces, and they usually just get you in the vicinity of the problem without really telling you the cause. This was best illustrated with the standard exception that was thrown when a hostname failed to resolve, where the message did not contain the hostname. This one was solvable (and did get solved AFAIK), but in a lot of other cases, the relevant context is not available at the depth where the exception is thrown, necessitating exception-wrapping.
win311fwg 6 hours ago [-]
> In the overwhelming majority of cases, you want to trivially send the error up the stack to be handled

There is no case where you would ever trivially send the error up the stack.

First, if your function doesn't have any meaningful information to add, you need to seriously question why the function exists. It is almost certainly not adding anything of value and the function that originally produces the error can just as well be called directly. No need to trivially pass an error when the useless "middleman" function doesn't exist.

Second, even if you still decide that a function that doesn't have worthwhile information is still worthwhile having, if you pass someone else's error straight through then you become forever coupled to the implementation of someone else. If you, for example, pass a SQLite error and then later decide you want to use Postgres, now you have to emulate SQLite errors every time Postgres produces an error, bringing you back to square one while also having one hell of a confusing API. Unless you hate other programmers and are purposely trying to make their life a living hell, the only sensible approach is to produce new error values at each step so that you can maintain stable sentinels/types.

A good language solution for errors might make it look like you are trivially passing an error up the stack while using some other method to attach the necessary metadata, like we see in some other languages, but nobody has yet figured out how to make that fit into Go. It is generally agreed upon that Go would greatly benefit from this, but until someone rolls up their sleeves and solves it...

ndriscoll 6 hours ago [-]
Functions exist first to give names to conceptual blocks, and should generally be defined by "level of abstraction." i.e. you give a name to some task that then perhaps calls some low level data validation or manipulation functions which can return errors. Your business process might not care which task had an error, so it just bubbles up to the higher level coordinator (e.g. a handler just returning errors to a router).

You do not need to have new wrappers at every level. That's what interfaces are for. e.g. if all you're going to do is retry up to N times and log, and you don't need special handling, you just call String() or whatever. But you still want libraries to return domain errors so that you can handle them if you need to, or for tests, etc. And you can have some layer in the middle to make like SQLError or DatabaseError.

Right I'm saying Scala does exactly that, and has libraries that e.g. propagate stack traces across fibres automatically and invisibly. There's prior art to observe. It's not some mysterious unsolved problem.

win311fwg 5 hours ago [-]
> Functions exist first to give names to conceptual tasks

Right, and conceptual tasks will almost always have information that is usefully attached to an error. There are exceptions, but even in those exceptions you still have to ensure you don't leak implementation details, so you still cannot trivially pass the error through.

> Your business process might not care which task had an error

That's true, but you would never write upstream functions with the business process in mind. That is for the downstream functions to determine. Doing so would couple an upstream function to the business process, making it difficult (maybe even impossible) to use again when the next business process wants to reuse it, which would be complete insanity. A function is written to provide what makes the function useful for the sake of the function itself. It is up to the caller to decide what facets of that are useful for the business process being implemented downstream.

> You do not need to have new wrappers at every level.

You absolutely do need them. The language can work to hide that they are being created, but that does not preclude the necessity of them. This is most definitely a solved problem in other languages, but it remains that nobody has figured out how to take those ideas and apply them in Go. What was done in another language cannot be lifted wholesale and simply dropped into Go. The world is not quite so simple. It remains an unsolved problem in Go.

And understandably so. Who has time to work on solving the problem when there are comments on HN complaining that nobody has solved it yet to be made?

win311fwg 6 hours ago [-]
> Reducing syntactic noise is about legibility, not writing ease.

Exactly, which said proposal does nothing to improve upon. Despite the reduction in characters it looks exactly the same as the traditional way, offering no way to improve how one think about errors. That proposal was clearly thrown out there just to try and appease the "Go doesn't have error handling" crowd without any thought into what would actually make the language better. The goal may be noble, but that particular proposal was rightfully abandoned.

> The error boilerplate as it exists interrupts the actual logic

Huh? No matter what logic you throw at the problem, there is no escaping that error handling is part of the actual logic. And it is, by far, the most important piece of the logic. Engineering is all about dealing with failure modes.

I'll grant you that there is a category of problems known as scripting tasks where error states simply can mean letting the program crash and allowing the user to clean up afterwards, but Go is clearly not trying to be a scripting language.

ndriscoll 5 hours ago [-]
I agree the ? proposal seems bad, which is why I didn't speak directly to it (but gave do notation as an example of a better solution that addresses the concern about special syntax for `error` specifically). Just the idea that explicit if err! = nil return err everywhere is somehow useful.

My experience with high level banking and low-level networking applications is that the default path for error handling is that you want to bubble up to central handlers the vast majority of the time. There's a reason why exceptions are a popular language feature; they're just hard to make work with fibres. With scripting you often don't want to handle errors at all. Just set -euo.

flanked-evergl 13 hours ago [-]
What makes these features unnecessary in 2024 but necessary in 2026?
hwc 10 hours ago [-]
On the other hand, I've found that for every real-world application I've written in Go, I have not found myself missing any of the containers C++ has had since 2003. I didn't really ever need generics either. I only use them to make it to make it clear which functions don't rely on specific properties of the type they operate on.

Yes, there are occasionally really good reasons to use an ordered map or a priority queue, but I haven't needed either in years.

JamesSwift 7 hours ago [-]
Most generics code is for library authors. Having generics allows you to write ergonomic algorithms for eg channels instead of forcing every single app developer to reinvent the wheel and run into the same footguns
bheadmaster 11 hours ago [-]
Language is more than just its syntax and features.

The most important "features" of Go are fast compilation, orthogonality of features, and easy development.

Their propositions may "look like everyone else" if you're only looking at surface syntax, but there's a reason why it took 10 years to design an acceptable generics proposal, and the result is that compiling generic-heavy code is almost as fast as compiling plain Go.

Go being strict about features it accepts is not an ideological thing, but a practical one. If Go could have all the features in the world while still being easy to use, fast to compile, and internally coherent, it would. But it can't (see: C++, C#, Python).

gritzko 15 hours ago [-]
Java started as a language to write apps on the Internet (applets). Then, it evolved into an elephantine corporate-focused language, because that's where the money is. I remember those Java applets that took minutes to load. The Web was taken over by JavaScript instead, which was famously coded in ten days.

Go used very particular shortcuts to make its GC'd runtime lightweight enough and the language simple enough. But, due to Conway's law or something else, it was destined to become a corporate-focused elephantine language, gradually.

I remember 10 years ago I believed that Go lacked something like STL. Later I changed my opinion cause I started to realize how much overhead red-black trees and suchlikes introduce. Especially in GC'd systems. This abstraction Jenga may indeed look shockingly absurd when you see all the moves in the system, not just your layer.

In performance-critical cases, I personally use ABC, a C dialect with solid containers. Those are basically chunks of RAM with fixed-bit-layout records in them. Vectors, hash maps and hash sets, heaps and queues are all just arrays. If we only needed that, we might have stayed with C. Solid containers require no malloc() and no GC. Can mmap them and you have a database. Can send them over the network as-is. That is the ultimate 80/20 thing here. LMDB is another example.

But if you keep adding features, 80/20 is no more and your Go becomes an uglier Java or Rust.

16 hours ago [-]
elktown 9 hours ago [-]
Or it’s just people with different opinions that took charge.

I find it funny reading sometimes how my country learned to conform on something that was previously a bit unique and people are like ”yeah, even they figured out it doesn’t work!”. No, you dingus, the people that wanted to conform were just elected. It worked perfectly fine otherwise.

vander_elst 10 hours ago [-]
I find it so sad that people wasted millions of hours and lines of code rewriting over and over basic constructs that should have been on the language in the first place. How many years before we finally get sum types?
epolanski 10 hours ago [-]
It's not like your idea is bad, is that each abstraction eats in one of the fundamental strengths of Go (simplicity and compilation times).
gadflyinyoureye 4 hours ago [-]
Go was never simple in action. The fact that you'd panic a nil map but not a nil slice is a foot gun. It's a pretty big foot gun. It's just one of the many foot guns.
nasretdinov 1 days ago [-]
Well, better late than never. Stuff like sets or a typed heap is long overdue. Maybe they'll even add iterator API for database/sql results this decade too (something like my pull request for sqlx https://github.com/jmoiron/sqlx/pull/990 but maybe more polished)
nasretdinov 1 days ago [-]
Also having stuff like a concurrency limiter (instead of doing weird var limiter chan struct{} and using it as `limiter <- struct{}{}` and `defer <-limiter`) as a library function in `sync` package would be great too.
astonex 23 hours ago [-]
There is actually a way to do this with errgroup provided you can work with func() error signature

https://pkg.go.dev/golang.org/x/sync/errgroup#Group.SetLimit

inigyou 22 hours ago [-]
Error 403. Summarize?
theowaway213456 21 hours ago [-]
errgroup has a SetLimit function to control the max number of concurrent go routines running at once.
arccy 23 hours ago [-]
aatd86 1 days ago [-]
But I guess the issue is that oftentimes, it is more of a distributed system coordination issue?

What use case do you have in mind?

smithcoin 17 hours ago [-]
You’d have a better chance of getting your PR accepted into https://github.com/Vinovest/sqlx
everybodyknows 3 hours ago [-]
> Since the addition of generics in Go 1.18 and iterators in Go 1.23, it has become possible for library-defined types to achieve comparable ergonomics to built-in types ...

For those who've been following Golang more diligently than myself: Is there a way now to define a slice-based type that enforces strict typing of its index, and yet preserves the compactness of the standard syntax "s[i]"?

dgunay 12 hours ago [-]
It's cool that they're doing this but with iterators and soon in 1.27 generic method parameters, you can already DIY most of this with little effort. I've got iterators at work for nearly everything I could want, small libraries for extra mapping, filtering etc operations, and with agents going back and actually refactoring old code to use them is easier than ever.
ncruces 9 hours ago [-]
Well adding the language features is a prerequisite to making these libraries possible.
kamma4434 16 hours ago [-]
Welcome to Java, where Collections are the bread and butter of every programmer since 1998.

While you are at it, I humbly suggest to add composable streams too, that we had in 2014, and that make working with collections way more pleasant.

(Jokes aside, in Java it is very nice that you can start with a generic ArrayList and turn it into a linked list with one single keyword change and no code needs changing, or that you can turn any collection into a synchtonized or readonly doppelganger with one line of code. Collections are nice and I miss them in Golang)

pjmlp 15 hours ago [-]
Actually welcome to Smalltalk, 1980's, because that is where collections, and iteration with blocks, comes from as inspiration to Java, and all the folks that think LINQ was a .NET invention.
Zambyte 6 hours ago [-]
And, as with most important lessons in programming, welcome to LISP in the 1950s, because that is where Smalltalk got its inspiration. :-)
tzone 11 hours ago [-]
People use Go vs Java not because of the language differences but because of massive improvement that GO runtime is compared to JVM.

It is crazy that people still don't understand why JVM sucks, and why GO's approach to minimize GC pause latency is far superior design decision compared to whatever JVM has been trying to do with its GC iterations for god knows how many years with gazzillion different variants that all suck in different ways.

vips7L 3 minutes ago [-]
Pretty outdated take. Java’s GCs are a generation ahead of Go’s.
Pooge 8 hours ago [-]
I'm the biggest fanboy of Go, but since Java 25 the default garbage collector (ZGC) is very similar to Go's.
tzone 3 hours ago [-]
Garbage collector alone can't do what happens in Go language+runtime. Simplest example is that there is no way to allocate fixed arrays with non-pointer structs in Java. That is just not possible in the language.

Design of Go allows programmer to rewrite their program to make it as GC efficient as needed. You can even have essentially zero GC overhead and do stuff manually for really high performance needs. And you can also write regular code when GC isn't a big deal.

Those options simply don't exist in Java language. Your only bet in Java would be to embed some C code which is a nightmare of its own.

There is a reason why almost all backened systems that run on JVM are a huge pain in the ass even at moderate scale. They all end up rewriting parts in other languages and at the end just rewriting the whole thing.

age123456gpg 3 hours ago [-]
Very similar, in the same way non-compacting and non-generational collector is similar to compacting generational :shrug:
hashmash 7 hours ago [-]
Low pause collectors like ZGC and Shenandoah must be enabled explicitly. G1 is still the default.

It should also be noted that the low pause Azul C4 collector was available in 2010, but it was a commercial product.

Pooge 7 hours ago [-]
You're right; apologies! I set the JVM flag quite some time ago, haha.
shikck200 14 hours ago [-]
Java? No thanks. I have some horrible memories from the ugliness, verbosity of Java. The cherry on the cake is the huge hog of an runtime called the JVM. Also java semi-forces you to have some bulky IDE. Last i looked there was no core java lsp server bundled in the tooling.

Java is the enterprise language that make programming suck.

vips7L 2 minutes ago [-]
Go is far more verbose and uglier than Java ever will be.
Shish2k 12 hours ago [-]
None of that is anything to do with collections
jiehong 24 hours ago [-]
Well, finally!

I wish they wouldn’t mix mutation methods in there, but ok.

improgrammer007 23 hours ago [-]
First they said they won't add generics. They violently defended that decision. Developers bent over backwards to make it work without generics. Some even wrote long blog posts defending Rob Pike's decision. Some wrote posts arguing against it. Now the Golang team adds them. Why waste so much developer time? It's not a few months. It's several years. This industry is seriously a clown show tbh.
pstuart 23 hours ago [-]
Core members of the language team (Robert Griesemer and Ian Lance Taylor) argued for generics from the very beginning. The team resisted because they didn't know how to do it without sacrificing speed of compilation.

Rob Pike did a lot of defensive work to deflect it but I'll quote him here on the issue when he said "There are no plans for generics. I said we're going to leave the language; we're done":

"I meant there are no plans for generics. That's not the same as saying we plan not to do generics. It just means we don't have a plan."

You take it as a conspiracy against developers when it's really a small team trying to find their way the best they can.

pjmlp 14 hours ago [-]
You mean how Ada, Delphi, D, OCaml compile?
pstuart 3 hours ago [-]
And your point is?

They didn't know how to do it "correctly" -- it took outside help from Philip Wadler (who helped with Generics in Java) to make it work acceptably.

Of course the core team were a big bunch of dumb old stupidheads and they made a dumb language for dumb people, so you win, you're smarter than them.

improgrammer007 23 hours ago [-]
It's an utter waste of time for developers, business, everyone. Millions of lines of Go code have been written without generics. Libraries have been written. Support, maintenance, cost, etc. This is why one shouldn't pick languages that regress in features from the get go. Now developers will waste time migrating the code to stdlib. This is not solving problems. This is doing tech for the sake of doing tech. Wasting everyone's time. Remember that code is not the deliverable.
wbl 21 hours ago [-]
Nothing was broken in the change: there is no need to migrate.
jppittma 22 hours ago [-]
Claude will migrate your whole repo in an hour.
kokada 17 hours ago [-]
I assume they will eventually add those to `go fix` too, so you don't even need Claude for the most basic refactors (the more complex ones, sure).
pstuart 22 hours ago [-]
I'm confused by what language regression you are referring to.

> Now developers will waste time migrating the code to stdlib

Why? If it works now it works. Refactoring tools exist, and LLMs make this trivial.

You just seem to hate the language and everything about it, and that's your right but I think your arguments are specious and ignore that most language that go mainstream evolve and that comes with tradeoffs (python2 -> python3, rust in general, etc).

And as far as deliverables go, the code is absolutely foundational to that and Go was made to be maintainable by codemonkeys such as myself.

Anyway, the language and the changes noted in the OP apparently aren't for you and that's ok -- there's plenty of languages out there for everyone's taste.

20 hours ago [-]
9rx 12 hours ago [-]
> You take it as a conspiracy against developers when it's really a small team trying to find their way the best they can.

Especially within a company more powerful than the individuals. The project was done, at least feature-wise, but then Google set it free to become a community-driven project, which opened the freedom to do new things again: https://go.dev/blog/go2-here-we-come

pphysch 23 hours ago [-]
At this point, the "damage" has been done and even skeptics of generics/iterators should applaud this proposal since it means burying some of that added complexity behind straightforward stdlib interfaces.

Unless they are just here to complain, of course.

saturn_vk 23 hours ago [-]
Violently?
rapnie 23 hours ago [-]
Too much. More like vehemently. Perhaps parent meant to say that.
improgrammer007 23 hours ago [-]
Yes, just used the word for emphasis :-)
amazingamazing 23 hours ago [-]
What’s wrong with meeting demand?
improgrammer007 23 hours ago [-]
Nothing is wrong. What was wrong before when they vehemently argued against adding it? Is that design principle/core value lost now?
ninkendo 23 hours ago [-]
Reminds me of when Apple finally moved the iPhone to USB-C… they defended lightning for the longest time, but then when when they finally did the switch, all I could think was “the last N years [0] of lightning accessories I’ve bought are now ewaste”… once it became clear USB-C was going to be the future, every year they weren’t using it was another year of future ewaste building up.

Every year go didn’t have generics was another year of workarounds and tech debt building up that would have otherwise been able to be written the right way from the start. Unlike ewaste though, it’s probably impossible to quantify.

[0] I’d probably peg N as the years between when they gave MacBooks USB-C ports for charging, up until the iPhone got them. It’s clear Apple knew they were gonna need to move to it eventually… every year in that period represents a year of lightning cables people bought that could have been still-useful USB-C cables today.

kokada 17 hours ago [-]
Technical debt, sure. But you could argue the same for any new feature added to a programming language, without having X you will need to workaround with Y, generating technical debt.

To be clear, I was one of those people that only started to use Go after generics. But for most of my projects, generics is less than 1% of the code base, so it is not like lack of generics was a huge issue. I think it is more of a problem for libraries in general.

amazingamazing 22 hours ago [-]
It is not a monolith, maintainers change? Why does it matter so much to you anyway? You can choose not to use generics
win311fwg 13 hours ago [-]
Huh? First they said they would: https://youtu.be/rKnDgT73v8s?t=3267 After a decade of nobody coming up with a solution that did turn to believing that Go would never be able to add generics. That is true. The air of defeat did become quite strong. But the Haskell guy did eventually came along to share his expertise and the rest is history.
athorax 1 days ago [-]
On one hand I'm glad to see this being added, but its becoming obvious building generics into the language as-is just isn't a good fit. Hopefully Go v2 can solve this at a more foundational level while still allowing interop or easy porting form current go code.
nasretdinov 1 days ago [-]
Why isn't it a good fit? The design prioritises readability of code that uses generics vs writing generic code (which is in line with the overall language philosophy). It also does it in a way that doesn't impact compilation speed or add too much complexity, which is also in line with the language philosophy.

If you don't like the fact that not all of standard library has been refactored to support the new language features -- I think it'll come over time. Once these features land into the standard library they can't be taken away, so the language authors take their time to make sure it's designed well.

I don't see anything going obviously wrong here.

TheDong 20 hours ago [-]
I agree it's not a good fit.

Go is a language built for people who don't wish to learn any math or CS theory, for people who don't wish to be "computer scientists" but rather "grug-brained programmers".

The new datatypes will mean having to read things like "sz := sx.Union(sy)", and the union operation between sets is too math-like, and thus makes it less readable.

"Advanced" data-types, like sets and heaps, only make code more readable to okay programmers, it makes code less readable to the average go programmer. To the average go programmer, a union operation is more readable as a for loop which does not have any math-y sounding name at all.

rattlesnakedave 19 hours ago [-]
some of us that have to work with people like you are happy that you're constrained by Go.
overfeed 15 hours ago [-]
My wish (curse?) on everyone who puts language "expressiveness" on a pedestal, is that their very clever colleagues express themselves creatively, in every codebase they set eyes on from now till eternity.
bananamogul 1 days ago [-]
I thought the status of Go v2 was that the devs weren't saying it will never happen, but also were not working on it. There was some momentum that seemed to sputter out once generics were added.

"when should we expect the Go 2 specification that breaks old Go 1 programs?

The answer is never. Go 2, in the sense of breaking with the past and no longer compiling old programs, is never going to happen. Go 2 in the sense of being the major revision of Go 1 we started toward in 2017 has already happened."[1]

Granted, this post was more about if there will someday be a Go that will break backward compatibility. But it sort of answers where Go 2 is as a side effect.

[1] https://golang.google.cn/blog/compat

orf 1 days ago [-]
Why is it becoming obvious?
troupo 1 days ago [-]
Go is rediscovering Guy Steele's Growing a Language from first principles, at a much slower pace: https://youtu.be/_ahvzDzKdB0?is=qZdfiT3792XyHxSJ
silverwind 1 days ago [-]
It's sad that such basic stuff took this long. If we're lucky we might even see a `Map` function in our lifetimes.
PrimalPower 1 days ago [-]
The beauty of go is YAGNI. Language design makes it much harder for people so do stupid and cute things.

During my design process if I start realizing that I’m missing maps, More expressive Types, Or more complex polymorphism. I ask myself if I really need those things.

If I really do. I move off of go.

That’s the beauty of the language. Go does not need more complicated language features because it’s can handle the majority of trivial software work without unnecessary complexity.

The language does not need to solve complicated problems.

brokencode 24 hours ago [-]
Ok, and what if you realize you want these things a million lines in? Do you still move off of Go?

Generic programming isn’t some fancy research language feature like dependent types. It’s just a bare minimum feature in any modern typed language.

It’s perplexing that after C# and Java both notably shipped without generics initially then added them later that they decided to ship Go without generics.. only to end up adding them later.

tialaramex 23 hours ago [-]
I guess it's possible that C# and Java taught the wrong lesson (you can add this later) and that actually reduced the impetus to ensure Go shipped generics in 1.0

It is also entirely fair to say there's a lot of complexity here and so there's a risk you exceed your complexity budget which for Go as I understand it was very slim. It is a possible a Go 1.0 with more generics doesn't take off because too many people bounce off the extra complexity and so a decade later it's an obscure thing Google made once that has a few fans but not much adoption.

Or that extra complexity means Go 1.0 ships five years later, after Rust 1.0 has given people an appetite for better performance and better safety and its sharpest corners have already been knocked off.

typical182 22 hours ago [-]
From what I've seen, I don't think the core Go team was ignoring the lessons of Java or C#.

Here's a sample quote from Russ Cox from 11 years ago on this site: [1]

We have spoken to a few true experts in Java generics and each of them has said roughly the same thing: be very careful, it's not as easy as it looks, and you're stuck with all the mistakes you make. As a demonstration, skim through most of http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.ht... and see how long before you start to think "was this really the best way to do this?"

And of course, they asked other experts for help, including Philip Wadler (of Featherweight Java and Haskell fame): [2] [3]

We’ve been thinking about generics since work on Go began, and we wrote and rejected our first concrete design in 2010. We wrote and rejected three more designs by the end of 2013. Four abandoned experiments, but not failed experiments, We learned from them, [...]

Last year [2018] we started exploring and experimenting again, and we presented a new design [...] and we’ve been working with programming language theory experts to understand the design better.

[1] https://news.ycombinator.com/item?id=9622417

[2] https://go.dev/blog/experiment

[3] https://go.dev/blog/generics-next-step#acknowledgements

danieldc 22 hours ago [-]
FWIW, C# generics are way better (ergonomics) than the Java ones (due to type erasure), so Java waited too much. History is more complicated though for Java, since it was either having some generics vs having none. See [this](https://softwareengineering.stackexchange.com/questions/1766...) for a lengthier discussion.
lilbigdoot 16 hours ago [-]
Yes, .NET had the benefit of coming second and using F#, which was originally essentially OCaml 4 on .NET, as it's testing grounds. Same for Async

I am considering .NET for one of my compilers backends because of the reified generics. .NET can even pass around an object with generic methods that get specialized via JIT at runtime each time it sees a new data type (with reference types sharing implementations). Which also ties back to having true value types

It's a shame it took so long for .NET core to come around because even today the platform carries a reputation for being windows first which hasn't really been true for many years now

metaltyphoon 16 hours ago [-]
C# was meant to have generics in day one, but it didn’t make the cut and it was introduced on the next version (2.0)
pjmlp 15 hours ago [-]
People always forget this other post when arguing for the home team.

"They are likely the two most difficult parts of any design for parametric polymorphism. In retrospect, we were biased too much by experience with C++ without concepts and Java generics. We would have been well-served to spend more time with CLU and C++ concepts earlier."

https://go.googlesource.com/proposal/+/master/design/go2draf...

typical182 5 hours ago [-]
FWIW, I do remember that quote.

It doesn't seem particularly damning to me, though, especially written by Russ Cox in hindsight. It's almost a truism that if you had spent less time on approaches that didn't pan out and more time on approaches that did eventually pan out, you likely would have arrived at a workable solution sooner.

For example, if the core Go team had spent more time exploring C#-like approaches (as some suggest they should have), it's possible that would have delayed the whole thing.

(btw, consider me a "long time listener, first time caller" -- I pretty much always pause to read your comments while flicking through discussions here, including I appreciate you often bring in historical context, even if I might have a different take, or even if I might have expressed your take differently ;)

xtracto 23 hours ago [-]
Maybe at some point it may even get the ternary conditional operator or a proper exception handling syntax.

Those things that Golang defenders say "dont make sense" until it's implemented, then 'it always made sense" and of course it's a good idea.

interf4ce 20 hours ago [-]
I'd welcome the ternary conditional operator but I hope exception handling never gets introduced (at least as I'm used to it from Java, C#, JS, etc.).

Exceptions should not be conflated with regular error handling, especially when they're allowed to bubble up from anywhere. I very much appreciate that functions that can return errors force the caller to deal with them, for the most part. True exceptions can already be thrown with panic, although I actually find it incredibly rare that I need to reach for that tool. I'd argue that when people talk about exceptions they almost always actually want "unhappy path" error handling.

Now, if Go wanted to add a sleeker way to handle those errors, similar to Rust's approach, I'd be very interested. Minimum three lines for every call to a function that returns an error does get a bit verbose, arguably hurting readability. A little sugar could improve readability without making error handling implicit.

cyberpunk 23 hours ago [-]
So your argument is that they should have gotten it exactly right first time and stuck to their guns?

I mean come on. The Golang team created a useful language people use for building real things — it’s easy to work with especially on large teams, and when the lack of generics turned out to be a pain point in the end (after years of production reality) they understood what the community wanted and actually… added them..

Now what, it’s not good enough?

No one forced you to use go.

No programming language is perfect. I personally find the language has served me well.

And after being so very pro generics myself, i actually find myself not even really using them that much apart from calling the slices module etc which has them under the hood anyway…

brokencode 21 hours ago [-]
Nope, I’m saying that the language that was seemingly designed with either an ignorance of or disdain for the hard-won lessons from decades of prior programming languages.

There was even this condescending attitude that Google engineers couldn’t understand fancy languages anyway, so they had to dumb Go down.

My criticism really isn’t even about Go itself. Yeah it’s improving, which is great.

My criticism is about this anti-intellectual attitude that has permeated the entire Go community since its inception. It’s like hearing that college is a waste of time from people who never graduated high school.

inigyou 21 hours ago [-]
my criticism is that if we make every language identical, we might as well only have one language. (C++, obviously)

There is room for a language without generics. There was a language without generics. Now there is not.

brokencode 21 hours ago [-]
Well here’s the thing on generics. Go always had generics since the very beginning. It’s just that only certain built-in types had them.

Slices, maps, and channels all were generic from day one. Same with functions like append, copy, etc.

Your criticism makes no sense unless you think Go shouldn’t have had generics from the start, which it did.

metaltyphoon 16 hours ago [-]
I think when people mention generics, they don’t mean builtins from the language but a language construct for generics.
inigyou 9 hours ago [-]
By that logic C has generics because pointers are a generic type - you can have a pointer to any type you want.
brokencode 6 hours ago [-]
Sure, lots of languages have some level of parametric type support.

This is just basic programming stuff and not limited to esoteric research languages.

Yet so many in the Go community treated it as some kind of language-ruining complexity.

pjmlp 14 hours ago [-]
Go only took off thanks to Docker pivot from Python into Go, and Kubernetes from Java into Go, after the respective teams got some Go folks into the project.

The usual RIX approach, followed the whole devops hype cycle that created all those CNCF projects half of which no one in devops space actually knows they exist.

blandflakes 3 hours ago [-]
And the kubernetes code and APIs still read like corporate Java for years after, too
improgrammer007 23 hours ago [-]
This. One should never pick a language that regresses in terms of features from the get go.
bborud 22 hours ago [-]
This is also why people eventually leave languages. Satisfy everyone’s wishes for long enough and you get lots of different styles of doing things and … «wow look at that much simpler language over there; let’s try that instead»
wannabe44 1 days ago [-]
Map function leads to poor code in Go. Function literals are verbose and inlining is far less agressive. It simply isn't the way of the language. Even python shuns map and filter in favor of comprehensions. A for loop is more readable than the lambda soup.
TheDong 20 hours ago [-]
> A for loop is more readable than the lambda soup.

Let's assume you have a slice of strings you want to uppercase. Which of the following is more readable?

    uppercased := slices.Map(inputSlice, strings.ToUpper)
    // or
    uppercased := make([]string, 0, len(inputSlice))
    for _, s := range inputSlice {
      uppercased = append(uppercased, strings.ToUpper(s))
    }
Let's say you want to parse a bunch of user-given inputs into durations, surely the following is more readable?

    parsed, err := slices.MapErr(inputstrings, time.ParseDuration)
I think map functions lead to cleaner code when used like the above, and a lot of for loops end up falling into those patterns.
wlamartin 17 hours ago [-]
I think in a language designed around FP ergonomics and expectations there's a lot to like about it.

In your second example, as a retrofit, I find myself asking "when does MapErr stop consuming the input list?", "which error gets returned if multiple errors could be returned?", "is it a errors.Joim situation", "if there are multiple errors how do I map them to the failed elements in parsed", "if I did want each parse to have either success or fail (think Result type) how would I represent this generically in a language that favours multiple return types"

There's a lot going on with that example that a for loop makes explicit and flexible for other choices.

ninkendo 23 hours ago [-]
IMO it depends on the language… to me, map/collect/etc are useful in languages that have the concept of immutable data, because you can initialize an array with a single call chain, and be sure that nothing after that can modify it.

What I’ve seen in the “for loop” approach that I can’t stand, are things like (pseudo code)

  var a = []
  for x in coll1 {
    a.push(foo(x))
  }

  do_stuff_with(a)

  // … further down the function

  for y in coll2 {
    a.push(bar(y))
  }

  do_other_stuff_with(a)
Reading code like that, is the first call to do_stuff_with(a) a bug, because it’s not fully built from both coll1 and coll2 yet? Or is the second call to do_other_stuff_with(a) a bug because a now contains more stuff than the developer probably thought? Can I safely move both loops next to each other, or does that break something subtle? If I need to pass a to a new function, where can I safely do this? Before or after I add from coll2? (In my actual times seeing this, a is really a map of cached key/values or something, and it’s kinda ok that the contents were different each time it was used, but subtle bugs emerged…)

IMO the sane way to do it is to just not incrementally mutate things like that, and stick with giving things a single place where they’re defined and initialized. Go doesn’t really help you here because there’s no such thing as immutable data. So just adding Map/collect or whatever doesn’t really buy you much.

tialaramex 22 hours ago [-]
Often the mutation might have performance benefits.

Of course if you're Rust the stdlib and compiler might conspire to optimise an operation you wrote which reads as non-mutating into an actual mutation which was faster.

This is another benefit of the "destructive move". If I consume X and spit out Y, the X is gone, so it's OK if secretly I just mutate X and tell you that's Y now.

tyre 16 hours ago [-]
Python uses comprehensions because whitespace sensitivity was a horrendous language decision, then couldn’t find a way to support multiline lambdas.

Comprehensions are not a well-designed feature but a consequence of poor design.

pjmlp 14 hours ago [-]
Nope, as someone there at the time, they are an influence how language like Haskell do them.

Which by the way has no issues being whitespace sensitive and having multiline lambdas.

The only reason Python doesn't support them is Guido not wanting to have them.

wannabe44 14 hours ago [-]
Comprehensions are way cleaner and more optimizable for the common case.
troupo 23 hours ago [-]
map functions are very useful for iterating over collections. Most functions iterating over collections are useful, because a lot of the data you're commonly dealing with is collections. And most collections are generic.

> Function literals are verbose and inlining is far less agressive.

> Even python shuns map and filter in favor of comprehensions.

That's the problem of the language design. And Python isn't the best language to turn to for language design

> A for loop is more readable than the lambda soup.

A for loop shoving modified items into a temp variable with append() that is then returned is less readable than a map function transforming data. Too bad Go decided to turn lambdas into unreadable soup.

inigyou 22 hours ago [-]
Go's whole philosophy was to keep the language simple. It's a shame they're abandoning that now and becoming the next C++/Zig/Rust/Java
pjmlp 14 hours ago [-]
Turns out programming languages are complex for a reason.
inigyou 12 hours ago [-]
But diversity is good. If I want C++, I already know where to find it.
pjmlp 7 hours ago [-]
The fallacy of "simple" languages is not understanding the history of programming languages, why and how they grow with the community, assuming they get any adoption at all.

No one among the folks that created Scheme or C, would assert R7RS or C23 are that simple.

9rx 12 hours ago [-]
Those who held that philosophy (Thompson, Pike) are now retired. Those who still have careers ahead of them want to have something to do.

The natural consequence of a "bullshit job" economy.

troupo 15 hours ago [-]
They threw many babies out with the bathwater chasing yhe rather unspecified "simplicity" and making parts of the lsngusge more complex to use as a result.
1 days ago [-]
pstuart 1 days ago [-]
Sounds like a win to me. I'd assume that many PL decisions come with with costs of either implementation or readability, and Go's conservative evolution takes that into account. Disclaimer: not a PL designer, just a codemonkey.

It's not a perfect language, and the process has not been without its pain points, but work like this makes the language more powerful and I feel like I get my money's worth when I use it.

Yes, I'm a Go fanboy but I'm not interested in language wars (e.g., yes Rust is more performant and correct but sometimes "good enough" is good enough).

cyphar 1 days ago [-]
On the other hand, design decisions made under one set of constraints can become problematic when you add new features that don't play as well with earlier design decisions.

For a concrete example, the fact you cannot define custom methods for external types in Go (a pre-1.0 design decision) means that you cannot write proper compile-time generic code to deal with some generic wrapping type (dumb example -- getting a sum of the perimeters of a generic set of shapes in an externally-defined collection type) -- you are forced to work around it with runtime type-switching. There are all sorts of arguments you can make about simplicity but this is an objective shortcoming of Go that is directly caused by generics being added to Go long post 1.0.

My take on this is that despite selfishly wanting more from Go for many years myself, adding more stuff to Go at this late stage is just slowly chipping away at Go's uniqueness with features that make a large number of people using them unhappy. (For example, while they make some APIs nicer, iterators turn a basic logic bug that is impossible with for loops -- forgetting to stop iterating when the loop has a "break" -- into a runtime panic. And they really suck to compose.)

aatd86 24 hours ago [-]
__For a concrete example, the fact you cannot define custom methods for external types in Go (a pre-1.0 design decision) means that you cannot write proper compile-time generic code to deal with some generic wrapping type (dumb example -- getting a sum of the perimeters of a generic set of shapes in an externally-defined collection type) -- you are forced to work around it with runtime type-switching. There are all sorts of arguments you can make about simplicity but this is an objective shortcoming of Go that is directly caused by generics being added to Go long post 1.0.__

I'm a bit intrigued by this: how would that work with compatibility between libraries, separate compilation and what not? My first instinct is that it would not be a good idea but I might be missing something..?

cyphar 18 hours ago [-]
In Rust this is solved by defining a local trait and methods implemented for a trait are only available if the trait is imported. This is in contrast to Go where methods are not namespaced at all. But there are almost certainly many other ways of solving the problem.

I was a little surprised how often I ran into this issue when using libraries that started defining structures as generic containers.

aatd86 2 hours ago [-]
Yes, so that is exactly what I don't understand, that makes compilation flow sensitive in a way that Go avoids by design in order to remain fast.
Hendrikto 12 hours ago [-]
> the fact you cannot define custom methods for external types in Go

Just wrap them. The external type is theirs. Make your own wrapper and do whatever you like with it.

People want every language to adapt to them, instead of adapting themselves to the language.

cyphar 9 hours ago [-]
That is the classic answer for how to do that in pre-generics Go. It doesn't solve the problem I mentioned.
pstuart 1 days ago [-]
Fair enough. Primeagen did a video recently renouncing his love of Go over the concerns you've raised.

That said, I'm assuming much of this "wobbly" functionality will live in libraries and will not be common in day to day coding (much as I've seen with generics so far). It's all optional after all.

I use Go because it's simple, capable, and been my prime language for over a decade and that skill enables me to be valuable enough for a decently paying job.

If I were younger with more energy and time on my hands I'd likely be a rustacean but I think I can ride out my career on this. YMMV.

cyphar 1 days ago [-]
I've maintained one of the major container runtimes (which is written in Go) for over a decade as well, I think I have a less rosy view of Go than you but I still think it's a nice language all things considered and still use it for some projects.
pstuart 1 days ago [-]
My goal is to be pragmatic about the issue (and everything else).

When I started with it I saw it as the love-child of C and python. Then saw it as a successor of Java.

I recognize that Rust will win this contest (although my understanding is that async still has sharp edges to round down). I'm old and tired and have lost the energy and focus for exploring new languages and believe that despite its shortcomings it will continue to have enough value to be useful.

Good enough will do for me. I tip my hat to the all the other PL contenders and wish them all well (except Java -- PTSD from that destroyed any love I had for the language).

wbl 21 hours ago [-]
Rust will not "win" when it targets a much different niche, any more than C won against Java or Scheme.
pstuart 3 hours ago [-]
I see a lot of overlap between Go and Rust -- with Go's "advantages" being simpler code to reason about and more ergonomic concurrency.

As Rust and its ecosystem mature and LLMs get better and cheaper, I imagine we'll see more ports of Go projects to Rust.

I love Go and admire Rust but I didn't have the energy to get through the learning curve, and Go does enough for me for what I need so I'll be ok if I never properly use or master Rust.

An ex-boss loathed Go and cited "but the nil pointers!" as his reasoning for his contempt and made sure to migrate the flagship project written in Go to Rust. People get emotional over languages but they're just tools and not worth fighting over.

troupo 23 hours ago [-]
> (dumb example -- getting a sum of the perimeters of a generic set of shapes in an externally-defined collection type)

There's a much more common example: dealing with external APIs that return JSON. Their response is trivially wrapped in Req<T>. Pre-generics Go would force you to write tedious duplicated boilerplate code for each request type, or just "cast to void*" with interface{} and hope for the best.

> adding more stuff to Go at this late stage is just slowly chipping away at Go's uniqueness

Uniqueness should not be the goal of a language.

tikhonj 1 days ago [-]
"Everything is a trade-off" assumes you're on the Pareto frontier.

Go is... very much not on the Pareto frontier of programming language design.

whateveracct 24 hours ago [-]
> "Everything is a trade-off" assumes you're on the Pareto frontier.

100%. it pisses me off so much that i have to hear this idea thrown around constantly.

fragmede 24 hours ago [-]
Somewhat. The trade off is it can be made more complex at the cost of its simplicity. You can argue that some of those tradeoffs don't in fact have to be made because it's not on the Pareto frontier, eg generics, but we'd have to have a specific discussion about specific language features instead of vague generic discission about the language.
pstuart 24 hours ago [-]
I find language wars tiresome at this point. There was no claim that it was a frontier language, or even that it was a great language. My point was that the Go authors do try to consider the impact of enhancements to the language, which I think is appreciated by many that use it.
valcron1000 21 hours ago [-]
22 years late, but better late than never.
1 days ago [-]
alfiedotwtf 16 hours ago [-]
No reference to Canadian Aboriginal characters in the comments :(
roundwego 18 hours ago [-]
A bit too late frankly. The snobbish arrogance didn’t help.
shevy-java 23 hours ago [-]
Golang's biggest problem is a certain company.
quchen 12 hours ago [-]
I'd say it's quite the opposite, Google is the only thing that made Go become somewhat popular.
znpy 1 days ago [-]
Looking forward to see G2EE being released as a specification /s
throw_m239339 23 hours ago [-]
Nothing wrong with J2EE back then if you were building a certain kind of entreprise application. EJBeans actually took care about a lot of business complexity for a n-tier application, it's just that the whole XML crap was absolutely egregious.

Go can barely parse an XML document natively so don't worry about G2EE I'd say...

I'm more worried about what have become of professional Javascript serverside these days, it's just nuts how people have managed to make it as complex as J2EE... Nextjs, Typescript,JSX, React, compilers, transpilers, ... and none of that stuff solves enterprise business logic...

znpy 21 hours ago [-]
Absolutely, i was just being ironic :)
pjmlp 14 hours ago [-]
What do you think Kubernetes is?

Go EE is the plethora of CNCF projects.

akiarie 24 hours ago [-]
Honestly the more I see this the less I like Golang. Generics was the worst thing ever added to the language. We're making it easier for library builders and harder for ordinary code to be written.
woodruffw 24 hours ago [-]
Is there a categorical division between “library builders” and “ordinary code”? That’s not one I’ve heard before.

(I’m aware of the difference between application and library code, but every large codebase I’ve ever worked in is a mixture of both.)

jerf 21 hours ago [-]
Do you use Go? Because it sounds like no. In the last four years I've encountered I think two uses of generics in the wild in a 3rd party library. Both quite sensible.

Anyone moaning about how it's ruined Go is either not using Go, or simply impossible to please.

If you hate Go... and hey, you do you, I've got my own list of languages I don't like... find a better complaint because this one is simply nonsensical. "It doesn't let me map/filter/reduce" or "it doesn't fix lock problems" or other similar complaints have some grounding in reality, but this one is just absurd. Generics aren't used enough to be "the worst thing ever". Fears about how Go would instantly turn into a language full of generics that take generic arguments that take generic arguments have proved to be wrong.

Quitschquat 15 hours ago [-]
This used to be the popular take not long ago. Now it's grayed out and unpopular.
troupo 23 hours ago [-]
Here's a quick example of ordinary code that is much easier to write with generics: https://news.ycombinator.com/item?id=49128954

Working on any collection is easier with generics. Working with anything that accesses data in uniform way (APIs, SQL etc.) is easier with generics.

pphysch 23 hours ago [-]
This proposal is literally about making it easier for ordinary code to be written without defining new generic types or iterators.
pif 13 hours ago [-]
People still calling themselves developers and choosing a language that was created for poor programmers...
foldr 12 hours ago [-]
It’s the same principle as accessibility. We are all poor programmers sometimes, just as we are all impaired in various ways at times even if we don’t have a disability.
win311fwg 13 hours ago [-]
The problem good developers have is that they develop software people want to use, and software that people want to use eventually requires more help, and once you need help then it is inevitable that you will need to bring poor programmers into the mix. A good programmer may respect the beauty of Haskell, but it isn't a practical option for them.

Ironically, only poor developers have the luxury of being able to choose something like Haskell as they never have to worry about building something anyone else wants to use.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 21:07:23 GMT+0000 (Coordinated Universal Time) with Vercel.