Rendered at 11:55:59 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
vander_elst 1 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 35 minutes 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).
DarkNova6 12 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 12 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 11 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 10 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.
hwc 48 minutes 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 6 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)
ako 8 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 7 hours ago [-]
That's fair. In addition, I'd add the great compatibility guarantees, and a community that makes easy-to-learn libraries.
LVB 7 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 5 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 3 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 10 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.
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."
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 4 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 4 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.
10 hours ago [-]
vlovich123 12 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 10 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.
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.
flanked-evergl 4 hours ago [-]
What makes these features unnecessary in 2024 but necessary in 2026?
gritzko 5 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.
hwc 53 minutes 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.
bheadmaster 1 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).
6 hours ago [-]
nasretdinov 15 hours 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 15 hours 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 13 hours ago [-]
There is actually a way to do this with errgroup provided you can work with func() error signature
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.
valcron1000 12 hours ago [-]
22 years late, but better late than never.
kamma4434 6 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)
tzone 1 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.
pjmlp 5 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.
shikck200 5 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.
Shish2k 3 hours ago [-]
None of that is anything to do with collections
jiehong 15 hours ago [-]
Well, finally!
I wish they wouldn’t mix mutation methods in there, but ok.
improgrammer007 14 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 14 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.
improgrammer007 14 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 12 hours ago [-]
Nothing was broken in the change: there is no need to migrate.
jppittma 13 hours ago [-]
Claude will migrate your whole repo in an hour.
kokada 7 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 13 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.
11 hours ago [-]
pjmlp 5 hours ago [-]
You mean how Ada, Delphi, D, OCaml compile?
9rx 3 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 14 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 14 hours ago [-]
Violently?
rapnie 14 hours ago [-]
Too much. More like vehemently. Perhaps parent meant to say that.
improgrammer007 14 hours ago [-]
Yes, just used the word for emphasis :-)
win311fwg 3 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.
amazingamazing 14 hours ago [-]
What’s wrong with meeting demand?
improgrammer007 14 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 13 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 7 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 13 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
athorax 16 hours 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 15 hours 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 11 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 10 hours ago [-]
some of us that have to work with people like you are happy that you're constrained by Go.
overfeed 6 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 15 hours 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.
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 15 hours 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 15 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 13 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 13 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.
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 7 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 7 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 5 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."
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 11 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 13 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 12 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 12 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 12 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 7 hours ago [-]
I think when people mention generics, they don’t mean builtins from the language but a language construct for generics.
pjmlp 5 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.
improgrammer007 14 hours ago [-]
This. One should never pick a language that regresses in terms of features from the get go.
bborud 13 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»
inigyou 13 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 5 hours ago [-]
Turns out programming languages are complex for a reason.
inigyou 3 hours ago [-]
But diversity is good. If I want C++, I already know where to find it.
troupo 6 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.
9rx 3 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.
wannabe44 16 hours 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 11 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?
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 8 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 14 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 13 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 7 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 5 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 4 hours ago [-]
Comprehensions are way cleaner and more optimizable for the common case.
troupo 14 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.
16 hours ago [-]
pstuart 16 hours 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 16 hours 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 15 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 9 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.
Hendrikto 2 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.
pstuart 15 hours 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 15 hours 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 15 hours 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 12 hours ago [-]
Rust will not "win" when it targets a much different niche, any more than C won against Java or Scheme.
troupo 14 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 15 hours 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 14 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 15 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 15 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.
15 hours ago [-]
znpy 15 hours ago [-]
Looking forward to see G2EE being released as a specification /s
throw_m239339 14 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 12 hours ago [-]
Absolutely, i was just being ironic :)
pjmlp 5 hours ago [-]
What do you think Kubernetes is?
Go EE is the plethora of CNCF projects.
shevy-java 14 hours ago [-]
Golang's biggest problem is a certain company.
quchen 2 hours ago [-]
I'd say it's quite the opposite, Google is the only thing that made Go become somewhat popular.
akiarie 14 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 14 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.)
Quitschquat 6 hours ago [-]
This used to be the popular take not long ago. Now it's grayed out and unpopular.
jerf 11 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.
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 14 hours ago [-]
This proposal is literally about making it easier for ordinary code to be written without defining new generic types or iterators.
pif 4 hours ago [-]
People still calling themselves developers and choosing a language that was created for poor programmers...
foldr 3 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 3 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.
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?
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.
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.
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)
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.
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
"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...
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.
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.
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.
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.
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.
Yes, there are occasionally really good reasons to use an ordered map or a priority queue, but I haven't needed either in years.
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).
https://pkg.go.dev/golang.org/x/sync/errgroup#Group.SetLimit
What use case do you have in mind?
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)
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.
Java is the enterprise language that make programming suck.
I wish they wouldn’t mix mutation methods in there, but ok.
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.
> 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.
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
Unless they are just here to complain, of course.
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.
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.
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.
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.
"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
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.
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.
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.
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
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
"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...
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.
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.
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…
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.
There is room for a language without generics. There was a language without generics. Now there is not.
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.
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.
The natural consequence of a "bullshit job" economy.
Let's assume you have a slice of strings you want to uppercase. Which of the following is more readable?
Let's say you want to parse a bunch of user-given inputs into durations, surely the following is more readable? 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.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.
What I’ve seen in the “for loop” approach that I can’t stand, are things like (pseudo code)
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.
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.
Comprehensions are not a well-designed feature but a consequence of poor design.
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.
> 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.
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).
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.)
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..?
I was a little surprised how often I ran into this issue when using libraries that started defining structures as generic containers.
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.
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.
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).
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.
Go is... very much not on the Pareto frontier of programming language design.
100%. it pisses me off so much that i have to hear this idea thrown around constantly.
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...
Go EE is the plethora of CNCF projects.
(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.)
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.
Working on any collection is easier with generics. Working with anything that accesses data in uniform way (APIs, SQL etc.) is easier with generics.
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.