Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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

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




While "fuck generics" might be a low-resolution characterization, it's not entirely inaccurate, and the efforts of Taylor (and perhaps others) notwithstanding, as long as anyone is writing things like "I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve," there's reason to believe it's apt enough.

As other respondents to the GP comment show, it's not at all hard to come up with that ostensibly elusive picture if you're attending to it. So I suppose the obvious takeaway is that they're still not really attending to it. Which is fine, Go clearly has its niche and its fans, and people who don't want a pretty good Blub have other options.


This is frustrating. Substituting an insult for politely declining (while leaving the door open) is not "low-resolution" or "apt enough", it's almost entirely inaccurate. Politeness matters.


"low resolution" is a perfectly accurate description of "fuck generics", which like any two-word phrase can't entirely capture the attitude of the golang team, but nevertheless does seem to capture something of gestalt of their approach.

Finer resolution would be if fusiongyro had characterized the golang team as saying "fuck off developers who want generics," which wouldn't have been as polite as the phrase "I don't have in my mind a clear picture of the detailed, concrete problems that Go users need generics to solve," but whose semantics are otherwise equivalent.


No. Unless someone finds a quote, the low order bit is that they didn't use the word "fuck" or any other swear word at all. You can't use the word "fuck" to accurately quote someone who didn't use that word.


Take a look at this article/talk https://commandcenter.blogspot.com/2012/06/less-is-exponenti...

He's explicitly rude. Sets up a strawman argument with the developer who can't imagine programming without generics. Mocks the people who want generics. Gasps in faux disbelief that it could be solved by types.

And then, when he goes in for the kill, to show once and for all that generics are pointless garbage:

He attacks type hierarchies and inheritance... completely missing the point by conflating parametric polymorphism and subtype polymorphism.

I think "Fuck generics" does a decent job of summarazing the rudeness, misinformation and ill-thought out arguments that the article contains about generics.


Rich Hickey's Tweet came to mind:

If you think you know how I ought to spend my time, come over and mow my lawn while I expound on the problems of dev entitlement culture.

I'm fine with RSC, Commander Pike, and those other benevolent dictators continuing to make much better decisions that I certainly ever would and more importantly to be super careful with what they add to the language. I write Swift, JS, objC, and Go. Go is the preferred language because it's simple and I have the entire SDK in my head.

I use Go a lot. I can't say i've ever run into not having generics being a huge deal.

Let's face it, for most programmers out there, generics is for type safe collections. If slices and maps weren't built into Go then i'd prolly have moved to something else.

That said i'd like to see more built in data structures


>You can't use the word "fuck" to accurately quote someone who didn't use that word.

Actually you very much can. It's the perfect word to describe certain attitudes, even if the person didn't use the word. It just translates to "who cares", "we don't need no stinking Generics", etc.

It can also convey many other things: http://reallifeglobal.com/how-use-word-fuck/


Bringing TOOWTDI from the realm of Python and Go to English, I see.

I suppose the argument I'm making does indeed depend on the premise that essential semantics of "fuck" can be conveyed in other ways. If you like, we could explore this by example.


Counting the weasel words.... 1. "might be" 2. "not entirely inaccurate" 3. "perhaps others" 4. "things like" 5. "the's reason to believe" 6. "apt enough"

And that's just in your first sentence.

My impression has always been that the Go core team is very open to the possible addition of generics, but also very wary of the very real downsides that generics have. Nothing I've ever seen from Rob or other core team members contradicts that. I'm open to citations if you can give any.

In contrast, a lot of Go users and proponents seem to be vehemently against generics, for wildly differing reasons. Some seem to be against them just for the lulz, others for crazy conspiracy theory or obscure philosophical reasons.

Me, I miss generics sometimes, but not enough to get riled up about it. I hope the Go folks come up with a clean, simple, and efficient way to get them, but until then I'm happy with the features Go has.


>And that's just in your first sentence.

Yeah, god forbid someone is not absolute in their statements, but gives the benefit of the doubt. I'd say it only counts as "weasel" word when you don't say what you mean to say or want to hide your true intention/reality. But, for all the "maybe" etc, the parent made clear what he thinks: that the Go team doesn't care about Generics. He's not going two ways about it, for this to qualify as "weasel" wording.

>My impression has always been that the Go core team is very open to the possible addition of generics, but also very wary of the very real downsides that generics have.

Ten years on, and just some a handful of posts and "proposals" (not bigger than 1000-2000 words) written, for something that should have been there for the start (and for other languages with even less resources, like Julia, Nim, Rust, Crystal, Haxe, etc, has been), does not look like "very open".

I'd get the "We have a certain philosophy about Go, with which Generics don't match". Or "we don't like them, deal with it". But this back and forth, and ifs and buts ad inifinutum borders on the passive-aggresive treatment of the issue.

The "very real downsides" are the same old engineering tradeoffs every language had to make. "We'll only add them when we can have our cake and eat it too" is a weasel approach.

>Nothing I've ever seen from Rob or other core team members contradicts that. I'm open to citations if you can give any.

If by citations you mean "all talk but no walk" -- and even the talk being always hesitant and amounting to "we'll see", "if there is some magic way" (and the perennial "we're always open to it"), then yes, that has been a constant for a decade.

Now, I've just written ~3-5K lines of Go, and my company has just a few K or 10K lines of Go in production (mostly a C shop). But while I like a lot (static compilation for easy deployment, concurrency, standard library, go fmt, etc), one of the things that stops me using it more is the Generics situation.


Have you given Nim a look? It sounds like it would be perfect for you. :)


What are the very real downsides that generics have?


I always assumed the Go developers were more worried about the effect of this feature on compilation time than binary size. After all, Go shipped static binaries only for years. But making the type checker more intelligent is going to imply more time spent type checking. It could also add time to parsing unless they choose the syntax carefully.


Do generics really add much compilation time? They sure do in C++ but that is because type checking C++ generics is based on substitution into the method body, which can have other generic calls inside of, which can lead to an exponential cascade and therefore exponential time compilation. Modern generics do not do that: a generic method invocation can be checked based on the type signature of the method alone.

For code generation you can do what Java does and erase generics (i.e. ignore them), in which case it will be no slower than code generation for manually erased code, which is what programmers have to write now. For good run-time performance you'd want to do specialisation, which may take longer but not much longer if the compiler is clever enough not to recompile the same method many times. C# does that and its implementation is actually fast enough for a JIT, let alone ahead of time compilation.


Even if you don't care about binary bloat (and I do care), it can introduce some of the same problems as dynamic typing.

If I am debugging some C++, and I find myself looking at templated function, then I can't easily see what types the template parameters are. Also it becomes hard to navigate to method calls etc.

C++ is a particularly bad example, because template metaprogramming is essentially typeless. But any form of polymorphism introduces these problems to some extent.

To be fair, that includes the run-time polymorphism already available in Go. Thus if generics allow us to replace some `interface{}` hacks with properly typed middle-men (even if they compile down to `interface{}`) then that would be genuine benefit.


Since C++ monomorphises every single template instantiation in a program, your debugger certainly should be able to tell you what the type parameters for that instance were!


A sufficiently smart linker will make that harder by removing functions that, byte for byte, are identical to one they already included in the executable ("identical code folding"; both gcc's gold linker and visual studio support that).


In my line of work I am very rarerly actully looking at a running executable with an interactive degger.

More often I am navigating through source code comparing it to logs, stack traces and other evidence that I can grab of what went wrong in production.

The source-level is important, because although I said "debugging" in my comment, what that very often comes to is first figuring out the intent of some other engineers from the thing they wrote -- and what they wrote is the source code, not the program state.


Binary bloat and general difficulties with how one handles variance in light of people's expectations.


> Binary bloat

That sure is a concern when just importing fmt increases your binary size from 900k to 1.6M…


Did he compare those shortcomings with the shortcomings of not implementing generics at all? Because that is the tradeoff here. After decades of research, a decade of go, millions of lines of public and private code, a decade of feedback, and dozens of languages with generics, it's obvious that the perfect generic system isn't going to just happen, so it's not perfect generics vs imperfect generics, it's no generics vs imperfect generics.


Link to top-level proposal: https://github.com/golang/proposal/blob/master/design/15292-...

If you scroll to the bottom, you can see 4 large proposals written by Ian over the years.


Except they seem to focus only on Java, .NET and C++, forgetting that generics were initially implemented in CLU back in 1975, and there were several programming languages since those days that had some form of generics being designed into them.


FWIW I have Liskov and Guttag (1986) on my desk. I haven't forgotten. I also explicitly address the "several since those days" in https://research.swtch.com/go2017#generics.


Any thoughts on Eiffel's implementation of generics?

https://en.wikipedia.org/wiki/Eiffel_(programming_language)#...


I liked using it at the university back in the day, and didn't had to repeat code.

Eiffel is a very powerfull language with good tooling, just failed adoption, because licenses were too expensive and software industry still has issues valuing quality.


Interesting to hear your experience. I had read a good amount about Eiffel and also large parts of Bertrand Meyer's book Object-Oriented Software Construction (quite a thick book too, and which uses the syntax and semantics of Eiffel, or something close to it, IIRC [1]), some years ago. Had found the language very interesting and also was impressed by it (and by the book). Read some case studies / success stories about it, which were good too. He and his team seem to have taken a lot of pains and thought a lot about the design as well as implementation of the language, from both an academic and industrial use perspective - so it seemed to me.

There is also an interesting anecdote about use of Eiffel in the book, here:

https://en.wikipedia.org/wiki/Object-Oriented_Software_Const...

That section shows the the 1st edition of the book did use Eiffel (as I said above).


With Eiffel tools you got the IDE with interactive development, including a VM for rapid prototyping. Then you would use the AOT compiler (via compilation to C) to produce shippable binaries.

So combining the easiness of interactive development with performance when it was time to ship the product.

It was also available before Java was a thing.

This is what I always kind of missed with Java and .NET, the previous generation of languages (Eiffel, Modula-3, Oberon(-2)) all had a mix of interactive development and AOT compilation for shipping release builds.


You seem to imply that Eiffel's solution was superior to Java's but nothing could be further from the truth.

The Eiffel compiler required four distinct sequential processes (note: not phases. I really mean that four programs needed to be run in sequence, and each of these four programs implemented who knows how many passes). Eiffel generated C++, huge executables, was incredibly slow (even with contract stuff turned off).

It was very hard to debug, with gdb routinely giving up on the complex .o generated. It was a very verbose language that implemented all known features under the sun, a bit like Ada and Scala.

Eiffel didn't take off for some very solid reasons.


> The Eiffel compiler required four distinct sequential processes (note: not phases. I really mean that four programs needed to be run in sequence, and each of these four programs implemented who knows how many passes). Eiffel generated C++, huge executables, was incredibly slow (even with contract stuff turned off).

This was not an inherent problem of the language, but one of the implementation.

I know this because I wrote a compiler for an Eiffel dialect for my Ph.D. thesis and there have been other Eiffel compilers without these shortcomings.

Also, EiffelStudio – which seems to be what you are talking about – generated C code, not C++ and had the option to generate an intermediate representation instead that could be mixed with compiled code.

> It was a very verbose language that implemented all known features under the sun, a bit like Ada and Scala.

It was actually pretty minimalist, not at all like Ada or Scala.

Code was verbose because (1) programmers were encouraged to annotate methods with contracts and (2) exactly because it was minimalist and didn't have a lot of alternative ways of expressing the same functionality.

Edit: There are two hard parts about writing an Eiffel compiler.

1. Getting the semantics of feature renaming during inheritance right. If you aren't careful, it's easy to introduce errors during this step.

2. Doing separate compilation for mutually dependent classes. This is where much of the complexity of the EiffelStudio compiler comes from. Java solved the problem by simply not allowing separate compilation in those cases. If class A has a member of type B and B has a member of type A, they need to be compiled together.

Everything else that's involved in writing an Eiffel compiler does not require more than than what you learn in your typical compiler course. (Though, obviously, experience will get you better results.)


>Also, EiffelStudio – which seems to be what you are talking about – generated C code, not C++ and had the option to generate an intermediate representation instead that could be mixed with compiled code.

I think that must be what I was referring to by my mention about melting or freezing in a nearby comment. Didn't remember the technical details. Interesting feature. Wonder if other languages have something like that.


That's EiffelStudio's Melting Ice stuff [1]. One of Bertrand Meyer's trademarks is his penchant for coming up with funny names for such features.

(Edit: Reading over it again, I realize that this may be read as criticism. To clarify, while I disagree with Meyer on some things, this isn't about disagreement. He is a teacher at heart – in fact, a very good teacher – and you can see some of his habits for keeping students engaged sometimes carry over into his writing.)

You don't see this approach really anymore, because these days it's so cheap to just generated unoptimized native code if compilation speed is an issue.

Obviously, if you have a JIT-compiler, then something similar happens internally in that some methods will be compiled, while others will be left in IR form (and sometimes, methods will even revert to using their IR). This was technology from back when CPU speed was still expressed in MHz.

OCaml had and still has both a bytecode and a native code format (for similar reason), but they cannot be mixed. OCaml's bytecode still sees use for (1) the bootstrap process, which allows you to build OCaml from scratch, (2) to run OCaml code on oddball architectures that the native compiler doesn't support, (3) to run code in the timetraveling debugger, and (4) when you need compact rather than fast executables.

OCaml's bytecode interpreter makes use of the fact that OCaml is statically typed and therefore doesn't incur nearly as much of a performance penalty as bytecode interpreters for dynamically typed languages.

[1] https://www.eiffel.org/doc/eiffelstudio/Melting%20Ice%20Tech...


Interesting, thanks for all the info.

>Obviously, if you have a JIT-compiler, then something similar happens internally in that some methods will be compiled, while others will be left in IR form (and sometimes, methods will even revert to using their IR).

I was going to say (in my parent comment to which you replied) that maybe that Eiffel's Melting Ice tech is something like Java JIT tech, but wasn't sure if they were the same thing.


Yes I implied just that.

The others already replied why.

Why on earth would one need to use gdb, given the nice graphical debugger of EiffelStudio?

Also it was way faster than code produced by Java, which I remind only got a JIT with version 1.3 and to this day only third party commercial JDKs do offer support for AOT to native code.

Java is also quite verbose. Verbose languages are quite good for large scale development.

On real life the majority of code is read not written, so I rather have it verbose and comprehensible than trying to make sense of a line full of hieroglyphs.


>It was a very verbose language

(Haven't worked much on Java recently, but did use it a fair amount some years ago.)

Isn't Java roughly equally verbose as Eiffel?

>that implemented all known features under the sun

At least based on looking at the Wikipedia article for Eiffel, it does not seem to have implemented functional programming, unless the article is out-of-date, or unless the agent mechanism supports FP somehow (not sure about that last bit).


>* The Eiffel compiler required four distinct sequential processes (note: not phases. I really mean that four programs needed to be run in sequence, and each of these four programs implemented who knows how many passes). Eiffel generated C++, huge executables, was incredibly slow (even with contract stuff turned off).*

That sounds like unrelated to the semantics of the language.


>With Eiffel tools you got the IDE with interactive development, including a VM for rapid prototyping. Then you would use the AOT compiler (via compilation to C) to produce shippable binaries.

I seem to remember that there was some intermediate form of language translation too - something called melting or freezing or some such (might have been two different things). This was for EiffelStudio, probably, not generic Eiffel stuff.

>This is what I always kind of missed with Java and .NET, the previous generation of languages (Eiffel, Modula-3, Oberon(-2)) all had a mix of interactive development and AOT compilation for shipping release builds.

Interesting. Didn't know that that generation had both. As an aside, I had read a good description about Modula-2 (not -3) in a BYTE article (IIRC, years ago), and it seemed to me at the time that it was a good language. Having had a good amount of Pascal background before doing a lot of C, I was interested to try out Modula-2, but probably didn't have access to any compiler for it at the time. Later I read that Delphi's feature of units for modularity may have been inspired by Modula-2's modules, along with the concept of separate compilation.


Units in Turbo Pascal come from UCSD Pascal.

The OOP features in Turbo Pascal are based on Object Pascal, which was designed at Apple for their Lisa and Mac OS systems programing language, with input from Niklaus Wirth.

Turbo Pascal was the reason why most PC developers never had too much love for Modula-2, because by Turbo Pascal 4.0 we had all the goodies from Modula-2 with case insensitive keywords.

Also, the compilers were more expensive than Turbo Pascal ones.

Incidentally Martin Odersky was the author of Turbo Modula-2, the short lived Modula-2 compiler sold by Borland.

I usually thank my technical school for having us go through Turbo Basic and Turbo Pascal before getting into Turbo C.

We were using Turbo Pascal 5.5 (I already knew 3.0 and 4.0) and 6.0 was still hot out of Borland's factory, which is why I've always been a fan of strong typed systems programming.


Interesting info ...

Turbo Pascal was the Pascal I'd used too, for a good while. Loved that environment. Really fast dev time and a fun language to work in.


The key difference between Eiffel and Java generics is that Eiffel allows for covariance by design. Obviously, this is unsafe and runtime type checks had to catch these cases. The goal was originally to resolve this through additional static constraints [1], but in the end the downsides always outweighed the benefits.

In the end, Eiffel stuck with covariance and a type system that is technically unsound, because the simplicity of the type system outweighed any hypothetical gains from making it fully sound.

Practical problems with Eiffel's generics arise mostly from the fact that, like Java, constrained genericity inherently relies on nominal subtyping, which makes it less expressive than it could be.

[1] https://www.cs.princeton.edu/courses/archive/fall98/cs441/ma...


I'll check that out, thanks.


Would you mind going into a bit more depth about Eiffel's generics? It's not obvious to me from Wikipedia how they differ from normal parametric polymorphism.


Did you read this, which is linked to from my earlier link?

https://en.wikipedia.org/wiki/Generic_programming#Genericity...

I may not be able to throw more light on it than that, sorry, since I'm not an expert on these areas, just interested.


Thanks, I completely missed that "Basic/Unconstrained genericity" was a subsection of "Genericity in Eiffel" when I first saw that page.


NP.


> Except they seem to focus only on Java, .NET and C++

C# isn't mentioned in any of the previous proposals, only Java, C++ and C.


C# does generics specialization at runtime, hard to do if you have no JIT :)


Thanks for the tip, you made me go google some things! [0]

Do you need a full-on JIT, or just a runtime? [1]

[0]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...

[1]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...


As I understand it it’s JIT in name only, doing the compilation on first run and then never again.


That is also a JIT, dynamic compilation doesn't require recompiling the code all the time.

The AS/400 uses a kernel level JIT, binaries are only JITted at installation time or explicitly via the command line.

The Lisp environments also only used JIT once.

Some implementations of Oberon would use bytecode instead of native code and JIT on module load.

There are many other examples.


This made me wonder if there's been efforts to fork golang and add generics as a proof of concept? In theory it should be much easier than a few of the crazy things people have done with c over the years?


It would be an wasted effort given the community's high resistance to them, better spend those hours contributing to a project where users value the work given for free.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: