Comment by ricardobeat
2 days ago
Preaching to the choir here, but this is why a lot of the Go community was against generics.
Especially in the era of AI assistants, the downside of writing out explicit types and repetition matters very little, while the upside of avoiding all this complexity is unmeasurable.
> the downside of writing out explicit types and repetition matters very little
That’s not the main reason. You can have a library by author X that provides a container type Heap[T] and you can use it with your type T which is unknown by X and requires no coordination. If the proto-generic maps and slices did not exist in Go it would not be a useful language at all.
This pain point was glaring in Sort and Heap in std. The argument was whether the complexity was worth it and compile time speed could remain so fast. Even the improved expressivity isn’t obviously good (famously the removal of goto was good because it reduced expressivity).
Just stating the arguments, I still haven’t made up my mind whether these limited generics was the right call. Leaning yes, but it’s important to be humble. It takes a lot of time to evaluate second order effects.
> Especially in the era of AI assistants
As an aside, I really don’t appreciate this argument without extremely strong merits, which we can’t possibly have. Not everyone is using AI assistants, nor do people use it in the same way. But most importantly it changes very little since code is not bottlenecked by writing anyway. Code is read more often than written, and still needs to be reviewed, understood and maintained.
As far as I've seen, a heap implementation using generics is not any shorter or simpler than the old `heap.Interface` - what it gained is reusability.
> Code is read more often than written, and still needs to be reviewed, understood and maintained.
Which takes us back to the points above. AI is really good at generating repetitive patterns, like plain types, or code that implements a certain interface. If you reduce the cost of creating the verbose code [at write time] we can all enjoy the benefit of reduced complexity [at read time] without resorting to generics.
Also not saying this as an absolute truth, it is more nuanced than that for sure. But in the big picture, generics reduces the amount of code you have to write, at the cost of increased layers of abstraction, and steering away from the simplicity that make Go popular in the first place. Overall I'm not convinced it was a net positive, yet.
Generic is not about reducing how many keys you press but how you abstract your logic from the type. In go, it reduces a lot code making it safer and faster. Handling interface{} was just painful.
This is an extreme example and I hardly think anyone writing go code on a daily bases will need anything close to this. I haven't and I have not seen any lib that does anything remotely similar to that. To be honest, hardly anything beyond the stdlib will need to handle generics. They aren't widely used but quite useful when needed, which I think it is sweet-spot for generics.
I don't share the same animosity against generics. I like the recent language addition to the stdlib and am also waiting for them to add some sugar to reduce the boilerplate in error handling.
> Especially in the era of AI assistants, the downside of writing out explicit types and repetition matters very little
Yeah, let's design languages based on the capabilities of code assistance /s
> Generic is not about reducing how many keys you press but how you abstract your logic from the type. In go, it reduces a lot code making it safer and faster.
No, this is not true for Go, at least for the current Go generics.
At runtime, Go generics can't be faster than generated repetitive code. Often, generic code is a little slower. Because sometimes values of type parameters are treated as interface values by the Go compiler, even if they are not.
> Handling interface{} was just painful.
Go generics are often helpless for this. Most use cases of interface{} are for reflection purpose and can't be re-implemented by Go generics. Some non-reflection use cases can't be also re-implemented by Go generics, because Go generics don't support type unions.
>> Especially in the era of AI assistants, the downside of writing out explicit types and repetition matters very little
> Yeah, let's design languages based on the capabilities of code assistance /s
I mean, that _is_ essentially the Go team's take these days, c.f. their previous blog post about error handling: https://go.dev/blog/error-syntax
> Writing repeated error checks can be tedious, but today’s IDEs provide powerful, even LLM-assisted code completion. Writing basic error checks is straightforward for these tools. The verbosity is most obvious when reading code, but tools might help here as well; for instance an IDE with a Go language setting could provide a toggle switch to hide error handling code.
Personally I expect that getting an LLM to write error handling and then have the IDE hide it sounds like a recipe for surprises, but I guess things work out differently if the goal is to have hordes of the cheapest possible juniors kitted out with tools that let them produce the most amount of code per dollar.
It's one thing to say that:
- an LLM can help you write a boilerplate `if (err != nil) { return fmt.Errorf(...) }` that actually matches the conventions for code base you're in;
- your IDE can "hide" those additional lines of code to reduce cognitive load while reading code;
- it's actually useful that those "hidden" lines are there when you're debugging and want a place to add a breakpoint, or some additional logging, etc.
This is very different from saying you should have an LLM auto generate half a dozen indentical copies of sync.Map, container.List, my.Set or whatever.Tree based on the types you want to put in your container.
I'm actually fine with an LLM as a more powerful auto complete, that generates half a dozen lines of code at a time (or slightly tweaks code I paste) based on context.
I would have a problem with a LLM generating thousands of lines of code based on a prompt "this, but for ints" and then it's a fork of the original, with god knows how many subtle details lost, and a duplicated maintenance burden going forward.
> that _is_ essentially the Go team's take these days
It is not "essentially their take". It is one of the point (a weak one for what my opinion is worth) but far from their main point. Their main point from the text is the same point they always make in these cases:
> Coming up with a new syntax idea for error handling is cheap; hence the proliferation of a multitude of proposals from the community. Coming up with a good solution that holds up to scrutiny: not so much.
> the goal is to have hordes of the cheapest possible juniors kitted out with tools that let them produce the most amount of code per dollar
I share the same concern here. I don't have a solid opinion on how that will turn out but I'm not too optimistic.