148 comments

[ 3.5 ms ] story [ 219 ms ] thread
Interesting timing as I had just read a great blog post about getting around the lack of generics in Go entitled "Living without generics in Go"[1] that I found to be very enlightening.

[1] http://www.weberc2.com/posts/2014/12/12/living-without-gener...

That was the way I used to write code when playing with Go, but in long term is necessary to write own wrappers for any tuple {collection, collection method, type}.
Interesting post, but what the author doesn't seem to realize is that even though he isn't doing much generic programming, someone needs to be able to do it to write the libraries he needs to use. The proposed approach is decent, but it reminds me of wrapping up STL container types in the amount of useless boilerplate needed to achieve a single function (but worse, because here the function is "type safety", whereas when you wrap an STL type it's about e.g. ensuring some invariant on the members of a set)
The author here. I'm not necessarily an opponent of generics, the post was just a "how to deal with the current situation", so keep that context in mind. :)

> someone needs to be able to do it to write the libraries he needs to use

I'm not sure what this has to do with what I wrote. As evidenced by the `container/list` package, a generic implementation can be distributed, and we can build our type-safe wrappers around that (if type-safety is really that important in your application--I haven't had much difficulty using the generic container as-is).

I do agree that the boilerplate is inconvenient (pretty much by definition). But it's fortunately also trivial by definition. People seem to think that these wrappers raise the total complexity of the program just because they contribute to the total lines of code (loc) count. Many people also think that if you don't use these type-safe wrappers that your program will be doomed to runtime errors.

I think both of these are big exaggerations, and that's why I wanted to write that post. Even in spite of Go's generics situation (I'm not entirely convinced about the degree to which it's a liability), I still find it to be the most enabling tool in my bucket.

This is Java-style type erasure done manually. So it has the same problem: speed hit due to lots of boxing and unboxing.
>As with any feature it should solve a set of problems, if the problem isn’t solved in the best way possible by the feature then it’s either not a good feature or of very limited value.

This is disingenuous -- just to set an artificial barrier against generics.

Go doesn't solve any problem in the "best way possible":

- "Blessed" containers like Go's hash tables are not "the best way possible".

- The way it handles goroutines/channels has issues (mutability/pointer issues, not pre-emptive, etc). Again, far from "the best way possible" (that would be Erlang maybe).

- The GC was far from the "best way possible" or even "really good". Especially on the earlier versions (and crap on 32-bit).

- Losing type checks by having to use interface{} for generality, or resolving to BS textually generated code with custom string templating is not "the best way possible".

So why only Generics has to be "perfect or bust"?

And then there's this gem, about the (lack of) need for generic data structures:

>map/slice suffice for most of the cases encountered in programming.

...

Or this "con", about having generic to help with functional fold/zip/map:

>The fastest solution needs to take into account when and which order to apply those transformations, and how much data is generated at each step

So, in other cases the hit from interface{} is OK, but suddenly now those operations have to be "the fastest solution".

(Not to mention that the fastest solution, application order etc are orthogonal to Generics).

"""So why only Generics has to be "perfect or bust"?"""

Ideology, and a push-back against outside pressure to include them.

It seems to be a rite of passage that everyone who gets to a certain point of familiarity with Go has to write an article justifying why you don't need generics. Austerity can be a tough way to live until you become a bit numb.
Another rite of passage is the "logger" library, where every Go coder I know (including me) writes a "better" logging library because the standard one is so terse. A few thousand lines of code later, everyone quietly discards their overcomplex library and reverts back to the standard log.

The same goes for most of the standard library "improvements" that people make. Http middleware is necessary until you grok the power of Handlers, ORMs are prevalent until you get that it's easier to write specific CRUD routines for your structs using the standard lib.

I don't think it's austerity any more. I think it's just putting a high value on simplicity, and I really appreciate that now I understand it better.

I'm happy to let the generics argument rage and smarter people than me resolve it. I don't need generics in my coding, happy to work around the occasional time I'd use them, but I understand the "argument from make" - if the Go team needed generics to build the language, then surely they're a Good Thing and we should have them.

I don't know. I program in C++ all day long--it took a loooong time to figure out the good patterns in the sea of options or to learn to interpret the cryptic and/or vague error messages (I just got an "invalid use of class" error today with GCC that contained nothing more than a line number for data). And that's not counting the sea of build systems, style guidelines, etc. And even with the generics situation, the amount of boilerplate in Go is a tiny fraction of that in C++.

I'm quite happy to yield control to sane defaults, widely-accepted conventions, and obvious idioms when I'm at home. If I ever need to write some high performance application, I'll definitely consider switching back to C++ (or perhaps learning Rust), but Go is great for rapid development of decently-fast-executing programs.

I think mostly it is an incompetence of Go's designers, no matter how they cover it up...
Then they should just own it and say "Go isn't getting generics ever." instead of making artificial barriers. Which their explanation totally is doing.

    $ python -c 'from __future__ import braces'
      File "<string>", line 1
    SyntaxError: not a chance
Whether you agree or disagree, it's not trying to bullshit you with fallacious reasoning.
If that had been re-worded to "if the problem isn't solved in the most pragmatic way possible" then I would suggest that the sentiment would be a) more in keeping with the general philosophy of Go and b) a justification, sort of, for only supporting map and slice.
I think you're interpreting that sentence a bit too literally. Clearly the developers of Go are interested in very carefully balancing language features with language complexity (seemingly both for language users and language implementers). And it is in that sense that they probably mean solve in the best way possible, namely to solve a problem in the best way possible with those two concerns - complexity, "expressitivity" - carefully balanced[1].

[1] Though one can argue that the word "best" seems inappropriate when the concern is a very subjective balancing act.

Thanks, didn't intend for it to end up on HackerNews - at least not yet. It's still the first draft, most of it I wrote up in ~2hours. I mentioned on the forum that this document (currently) is highly biased towards my views, this is unfortunate, but this can only be fixed after numerous reviews.

Thanks for pointing out the problems with wording. I'm slowly fixing those. I've changed that "best" to "As with any feature it should solve a set of problems, if there are better ways of solving the problems, those should be used instead."... it's better but not perfect.

"in other cases the hit from interface{}" - added that addition to the alternatives section.

Generics don't have to be perfect, but it must be actually useful and it mustn't compromise simplicity of Go.

Put a big comment on the top DRAFT!! STILL IN PROCESS!! or something.
It doesn't mention the major inconsistencies in golang at all.

Go has generics. For arrays, slices, channels, maps, and some "standard" library functions. Go has generic functions. "append" being the obvious example. Go has polymorphic functions : append, make, ... If you look at the compiler source, the type system has generics, to a large extent. It's simply not accessible to normal programmers, instead only allowed for golang's authors.

As if this is not bad enough. Go cheats the type system in thoroughly non-obvious ways to get more C-like behaviours that obviously do not improve safety or programmer productivity.

Go has shudder return value polymorphic functions. Range being the obvious, but not only example (range changes in meaning depending on it's parameters AND on what you assign the result to).

As for your boxing argument. As soon as you use reflect, you're boxing everything. Oh wait, if you use a package that uses reflect, of course you're also boxing everything. Surely that can't be much ... hmmm half the standard library uses reflect. Fmt, everything in encoding, text or html templates, rpc, jsonrpc ... No need for boxing, or compile-time function evaluation or generics (all present better solutions to this, for the CTFE solution see D-lang).

Golang even has functions with type parameters. Make and new being the obvious examples. Again, this is present in the type system (not just there, also in reflect, things like printf, ...). It's simply not made accessible to us lowly go programmers.

So can we please stop with the crap that generics aren't necessary ? That nobody uses advanced type system features ? Or that polymorphism isn't necessary ? It's crap, and obviously the golang authors don't actually believe that. They just think that only they can be trusted to write such functions and that their datastructures are all anyone ever needs. If you disagree with that assessment (and everybody will, soon) Go is not for you.

So Go is simply a throwback to pre-80s programming languages, and a perfect illustration of the frustrations that led to the development and extension of the C++/Java/C# programming languages. If you give people the minimal implementation of sorting an array of structs, it becomes blatantly obvious why other languages are necessary.

The more I write Go, the more I yearn for C++. There is nothing in the C++ language that I can't do for my own datastructures/functions/... That is a huge feature, and may I just say :

From my cold, dead hands !

Btw : there is a better solution to generics as well at compiler-level, that is used in things like the CLR. First, generate unboxed versions of functions where that makes sense. If specializations are possible for 1-bit, 1-byte, 2-byte, 4-byte and 8-byte primitive data types, expand those. Then for anything bigger, like structs, create a boxed implementation, because for structs there is no longer any advantage to working unboxed. Then make it possible to pass in the version to be used in a parameter, so you don't have a combinatorial explosion when many type parameters are given.

e.g. http://research.microsoft.com/pubs/64031/designandimplementa...

> It doesn't mention the major inconsistencies in golang at all.

It has little relevance to "Generics". They are simply how Go is implemented, the question is whether "Generics" as a user implementable thing should be added.

> CLR

From my quick reasearch, it uses runtime code generation and Go must run in environments where that is disallowed.

Regarding the CLR you have ahead of time compilers in the form of Mono for iOS, Windows Phone, Bartok, ngen and now .NET Native.

How the generic code generation differs from the JIT approach I don't know.

It has relevance to generics. Right now the question implies Go does not have generics, which is not true at all. The question should be reworded :

Go has generic types and generic/polymorphic functions. Therefore all the focus on that such functions are not necessary/useful seems entirely beside the point, the result of misunderstanding. Can normal Go programmers please be allowed to make use of that feature ?

Btw : there is a better solution to generics as well at compiler-level, that is used in things like the CLR. First, generate unboxed versions of functions where that makes sense. If specializations are possible for 1-bit, 1-byte, 2-byte, 4-byte and 8-byte primitive data types, expand those. Then for anything bigger, like structs, create a boxed implementation, because for structs there is no longer any advantage to working unboxed. Then make it possible to pass in the version to be used in a parameter, so you don't have a combinatorial explosion when many type parameters are given.

That sounds sensible.

I'd like to figure out a way to extend the concept of interfaces to cover use cases like generic containers, but I'm not quite sure how that would work.

>* Thanks, didn't intend for it to end up on HackerNews - at least not yet. It's still the first draft, most of it I wrote up in ~2hours. I mentioned on the forum that this document (currently) is highly biased towards my views, this is unfortunate, but this can only be fixed after numerous reviews. Thanks for pointing out the problems with wording.*

Thanks for not being defensive and taking my rather harsh critique lightly!

I wasn't trying to attack your specific document either, it's just that those things have often been repeated (often verbatim) by the Go-dev camp.

Basically, I have nothing to be defensive about - it's a summary of discussions, which means that any properly stated argument should be incorporated to the document, no matter what I personally feel about that argument. Although, the content has to be moderated somehow, I dislike deciding what is "properly stated" argument, but I don't really have a better idea how to do it either, at least not yet.

Personally, I stand in the middle of the generics discussion so I pretty much can see both sides as a valid approach. And it's a WIP and I know if one person writes it, it will be biased no matter how hard you try.

PS: I find the "straight to the point" comments much more useful - they are much easier to understand. So don't worry about it :)

Not trying to troll, but it's seriously depressing how much time is wasted on this language.
Trolling or not, comment is unproductive. Might I suggest offering alternatives such as rehashing the "rust is arguably a better design with similar goals" vs "rust's library isn't as complete and the language isn't stable" debate?

I have been writing Go code professionally nearly every day for 6 months. Would I rather be writing C? Probably. Python? Not on a project of this scale. C++? Toss up. Java? No - doing far to much interfacing to C libs for that. Rust? Probably. Go is far from perfect, but honestly not that bad.

What advantages does Go have over Erlang?
What advantages does Erlang have over Factor?
I don't know much about Factor, it's a Forth implementation right? Just inspired by Forth?

Either way, the example[0] I was greeted with on the homepage[1] is quite awesome. Does it have an actor implementation like Erlang? How does it handle concurrency?

0:

    USING: io kernel sequences
    http.client xml xml.data xml.traversal ;

    "http://factorcode.org" http-get nip string>xml
    "a" deep-tags-named
    [ "href" attr ] map
    [ print ] each
1: http://factorcode.org/
It can be learned by a programmer knowing only imperative C-family languages in a couple of hours, meaning I can hire any average developer and make him productive in less than a week. Not the same as teaching pure functional style with pattern-matching and prolog's syntax. Go is also much more efficient. It also produces static executables and can be easier to deploy -- or not, depending on the exact situation. It handles strings nicely -- anything other than Erlang's approach to strings is nice.

Erlang has other advantages, though. 99.9999999% uptime and hot code replacement are easier with it, for instance. Their ideal niches don't completely overlap.

I believe I can agree to the above statements.
Comparing Rust to Go is equally unproductive, given that they target wildly different use cases and embody dramatically different philosophies. You might as well compare Lua to Objective-C, or OCaml to Malebolge.
I'm at the point where I hope they never add them, even though I've liked them in other languages.

Once they do, you know not every "generics or bust" will be satisfied and the anti-Go hate will simply shift.

I say let the haters hate and keep generics as their focal point.

So, you argue to not add a feature to the language because it would fix one of the main points of criticism? That is silly, don't you think?
It is. The Go language devs should just own it and say "No". Will the arguments shift somewhere else? Maybe but maybe the "Go needs generics" folks will just go away.
>The Go language devs should just own it and say "No"

Which is the grown up, honest, thing to do.

But I'm not sure about the other thing you mention:

"Maybe but maybe the "Go needs generics" folks will just go away."

Why would they go away?

They ask for Generics because they have found some use for Go (say, because it has a OK standard library, or decent tooling and momentum compared to alternatives), but also found a need this feature.

Neither the "use of Go" they found, nor their need for generics will disappear if the language devs say "no". If anything, as stakeholders in the languge (a user is a stakeholder) they'd be even more pressed to change the language dev's mind -- down to the fork point.

How many years to go before go users/developers outside of google will fork "go lang" the way node.js users/developers did ?

the go-lang team at google is very smart. It's not that they have a huge amount of high-priority work other than generics. Why don't they address a summary of the sentiment on hacker news on generics ?

If you're a programmer, your life is made easier if you have access to generics.

If you're a language developer, your life is made harder if you have to add generics.

And if your language gets all the people that are easily satisfied with something "static and faster to write than C" why go the extra mile?

Especially if your goal is not building a commercially succesful language, or an advanced language, or a language to solve 2014's problems, but just to hack on what you have created.

Besides, being a great programmer and a great language designer are two different skills. Would a language created by Linus be that good?

>Once they do, you know not every "generics or bust" will be satisfied and the anti-Go hate will simply shift.

No, I don't know that.

Do you suggest they are lying and just hate go out of pure irrational emotion? (Despite some of the critics having writen thousands of lines in Go, or some like pjmlp have even had code in the standard libs).

Is there evidence to suggest that?

Does that hold true for other languages too? When people criticize a specific problem a language/technology has (e.g. Python's GIL or PHP's lack of proper language implementation with AST et al, SOAP for its verbosity, etc), is that out of "haters gonna hate" mentality?

Does that extend to that programmers cannot recognize constant pain points in a language, and those that complain about such things are irrational?

I find the idea expressed in the comment incoherent and illogical itself.

It's quite true, in fact. Look at Java's generics. Pre-Java 5, everybody was asking for generics. They got implemented. Now everybody complains they suck because they are a hack, they are slow, not that type-safe, made the language more complex, are not as powerful as C++/Ada/Haskell, etc. Nobody wants to go back to Java 4 (in which situation was worse than Go, tbh), but everybody (OK, most people) keeps complaining.

I'd myself be very happy with a hint of generics in Go, though. Something at the package level, that would be instantiated at "import" time (since the import keyword is supposed to hold some magic in itself) would have my preference.

There is only two ways to compile generics C++ (instantiation) and Java (type erasure) style. [0]

Alternatives to these are just manual or semi-manual variants. For example, Go people seem to like the "empty interface" approach. Well, that is Java-style type-erasure done manually. The code generation approach is just C++-style instantiation done outside of the compiler.

[0] http://beza1e1.tuxen.de/articles/generics.html

C# doesn't erase types, and it doesn't create a separate type for every possible variant.

See the ".Net Implementation" section here:

http://www.jprl.com/Blog/archive/development/2007/Aug-31.htm...

This interview with Anders Hejlsberg is also a good source of information

http://www.artima.com/intv/generics.html

So, C# does instantiation, but is usually clever about reference types.

I am not quite sure from the interview what happens about constraint types. It seems the reference is cast into an Interface type (IComparable) and used as such. In other words, boxing.

The arguments used for contrained type parameters can be checked by the compiler, so no casting is necessary at runtime

"... C# does strong type checking when you compile the generic type. For an unconstrained type parameter, like List<T>, the only methods available on values of type T are those that are found on type Object, because those are the only methods we can generally guarantee will exist. So in C# generics, we guarantee that any operation you do on a type parameter will succeed."

Edit (more explicit quote):

"When you say K must implement IComparable, a couple of things happen. On any value of type K, you can now directly access the interface methods without a cast, because semantically in the program it's guaranteed that it will implement that interface. Whenever you try and create an instantiation of that type, the compiler will check that any type you give as the K argument implements IComparable, or else you get a compile time error."

Furthermore (related to the CLR avoiding boxing costs):

"I'm just pointing out that we do fairly aggressive code sharing where it makes sense, but we are also very conscious about not sharing where you want the performance. Typically with value types, you really do care that List<int> is int. You don't want them to be boxed as Objects. Boxing value types is one way we could share, but boy it would be an expensive way."

What I wonder is: Take "SortedList<T> where T:IComparable". Now there is a generic add(T t) method, which needs to call t.compareTo(x). As add does not know the dynamic type of t, we don't know the vtable offset of compareTo for compilation. Thus the compareTo call cannot be compiled to "load method pointer from vtable; call it". We need something more expensive or JIT magic (traces,guards,etc).
What I wonder is: Take "SortedList<T> where T:IComparable". Now there is a generic add(T t) method, which needs to call t.compareTo(x). As add does not know the dynamic type of t, we don't know the vtable offset of compareTo for compilation. Thus the compareTo call cannot be compiled to "load method pointer from vtable; call it". We need something more expensive or JIT magic (traces,guards,etc).
The .NET generics are also interesting to contrast with C++ and Java since they are implemented in a virtual machine that allows interoperation between different languages. Not really applicable to the Go discussion, though.
Both Java and .NET also have a ahead of time compilation to native code.
Did you even read the article you linked to?
If they give us type safe c-like macros I will happily live without generics. This is from a Scala dev. I write Go because it's easier and less error prone than going through JNI. However the lack of any reasonable abstractions in Go makes it my last choice language.
What I find frustrating is that they seem to think that there are only two solutions - C++ (create a new type for each variant) or Java (erase the type information).

C# does it differently to either - see here:

http://www.jprl.com/Blog/archive/development/2007/Aug-31.htm...

(The section marked ".NET Implementation")

Edit: And here's Anders Hejlsberg talking about the design:

http://www.artima.com/intv/generics.html

> What I find frustrating is that they seem to think that there are only two solutions - C++ (create a new type for each variant) or Java (erase the type information).

That, at least, is correct. Generics can be erased (compile-time only) or reified (generic type instances exist at runtime).

C# uses reified generics, and Mono creates (created?) a reification for each parameter typeset, Microsoft's implementation creates the same underlying reification for all reference types as a space optimisation, but it still uses reified generics.

There is a good helping of dishonesty in using C++ as the "reified generics" example though, as C++'s templates do significantly more than just reify generics (template specialisation, code generation, etc…) and that added to the interactions between templates and other language features makes them significantly more complex than e.g. C#'s, Rust's, Ceylon's, Kotlin's, and most other instances of reified generics.

Whether generics are erased or reified is orthogonal to how they are implemented (whether the code is specialized or not).
The argument brought up regarding compile times is also a misnomer. C#'s compiler pre-Roslyn is already very, very fast.
As usual, it lacks discussion about generics in:

- Eiffel

- Ada

- Modula-3

- D

- MLton

- .NET

- Rust

- Haskell

- OCaml

- Sather

- BETA

- CLU

Even if they overlap, it would be nice to see them being discussed. Not all generics are born alike.

Personally, I don't care any longer. It is still better than just plain C.

That would be a great promo material:

Go: still better than just plain C.

Even beats Algol 68: http://cowlark.com/2009-11-15-go/

> Even beats Algol 68: http://cowlark.com/2009-11-15-go/

Isn't the point of the article that Go doesn't actually beat Algol 68?

> The answer is that they're both very, very similar, with much the same level of functionality. They overlap more than they differ.

> Go has more in the way of actual features --- interfaces, channels, maps, defer , fallthough , proper closures --- but Brand X is more consistent with its features. […]

> Go, on the other hand, is full of corner cases. […]

> Most killingly of all, it's full of examples where they did not consult the literature. […]

> Brand X doesn't have any of these issues. Oh, it's got issues all of its own --- for example, the oddities in the reference type system; no varargs functions; no proper object system; the lack of little bits of syntactic sugar like keyworded composite structure literals... but it feels complete in a way that Go doesn't. I can use Brand X to implement nearly all the features of Go. I can't use Go to implement the features of Brand X.

> The only major features that Go has that Brand X doesn't are proper closures, and the interface system. And I'm afraid that's not enough.

> I would rather code in Brand X than Go.

>Isn't the point of the article that Go doesn't actually beat Algol 68?

Sort of. The point is that it's not modern at all, that it's actually comparable to Algol 68 without resorting to hyperbole.

In some ways, the article says Go beats it, in some other Algol wins.

> In some ways, the article says Go beats it, in some other Algol wins.

Right, so Go does not beat Algol in the end.

And the article does conclude with preferring Algol to Go.

Go: still better than just plain C.

This seems to come up at every discussion about Go. What usually also comes up is how Rust is a much better designed language which solves real problems, while Go merely improves a little over C while leaving most of the same death-traps lying around.

Yet at the same time Go seems to have a much bigger adaptation than Rust. What's up with that? Are Googlers paid to create projects in Go, or are people genuinely happy to have anything which sucks less than C and stamped with a "final" badge of approval?

Go is older, so it has had more time to gain users. And go has gained users mainly from python and ruby, not from other compiled languages. People are genuinely happy to have anything which sucks less than scripting languages but still offers comparable development speed. That's where go is doing well.
>Yet at the same time Go seems to have a much bigger adaptation than Rust. What's up with that?

Well it has to do with Rust not even being 1.0 yet, whereas Go has been stable for 5 years...

Or with Rust changing some syntax in every point release for most of it's design cycle, so even early adopters had a difficult time.

Or maybe with Go having Google behind it, with the increased visibility it entails... (Rust, for one, never had huge Google Developer convention sessions exposing it to thousands of devs -- or any conventions for that matter).

And yet, we're already seen increased adoption for this pre-1.0 rust, major community playahs like Katz getting in the core team, more posts and libs every day, etc...

Being stable for five years rather than still being under development can be seen as a feature. It is a strong selling point of Go, actually : solving actual problems rather than making a perfect language. It's a perfect example of Stroustrup's quote about languages everybody hates vs languages nobody uses.
And again, people compare Go and Rust while they have completely different goals.

Go is about capturing dynamic languages' flow of development and put that on top of types and static compilation so you can improve early on performance and correctness (That doesn't even include inserting a "generic" way of coding concurrent processes).

Rust is much more about replacing C++ in features (from my little-knowledge POV): provide higher-level constructs to model your problem than raw C, with a heavy control over memory for maximum correctness and performance.

Rust may be better designed, yet I find it much more verbose and harder to understand than Go. While this may be a reason for the difference of adoption, a much bigger reason must be the difference in maturity.

>Go is about capturing dynamic languages' flow of development

The only features it has regarding that is GC, built-in hash-table and type inference. Hardly the gist of what makes dynamic languages flow a fast/nice one.

Plus Go was also advertised as "systems language" -- and besides, the same kind of programs Go is used for, servers, REST, network infrastructure stuff, etc, Rust will be used for too.

It's not like Rust is only (or primarily) for anything much lower level than Go.

> The only features it has regarding that is GC, built-in hash-table and type inference.

No, the real feature is understanding that a language doesn't stop at the syntax, the tooling and the environment are extremely important:

- unless you want to build multiple binaries in one command, there is no need for any build helper.

- hack-compile-test cycles are really short, to the point you can run simplest go programs as scripts

- go has its own package manager, allowing you to manage dependencies extremely easily (not technically specific to dynamic languages, but in practice often associated with them) (Note that I'd prefer if everything was managed by my OS package manager, but we're not there yet)

The go creators (and community) has spent a lot of effort in improving the overall development environment, and this is a characteristic I have seen more developed in dynamic languages (again, I'm not saying that it's tied to a type of language, but I have seen this more developed with the pythubyerlascripts)

> It's not like Rust is only (or primarily) for anything much lower level than Go.

It's not, It's just targeted at different problems. You wouldn't use Go to build a game engine [1] (you need tight control over memory and have some realtime requirements), and I'm not sure you need the tight control that Rust gives you over memory when you build an image processing server [2] (you'll need concurrency primitives for this)

[1] https://github.com/Jeaye/q3

[2] https://github.com/ReshNesh/pixlserv

Rust is a much better designed language which solves real problems

Yet remarkably people are solving real problems with Go. Despite all of these dire predictions and pontifications on here by so many mortally offended by Go's existence, people are simply making solutions and moving on.

I don't believe I've heard of a single significant solution with Rust. I mean, I'm sure one exists somewhere, but it seems that it's caught in the advocacy trap of people talking about how great it is (overwhelmingly in Go discussions, it seems), instead of building solutions with it.

> I don't believe I've heard of a single significant solution with Rust.

Servo is pretty much the motivating application for the Rust language. So you should keep your eye on that if you're interested.

I don't know what people keep comparing Rust and Go. It might be that they are both after the coveted replace C++ spot shrug.

That said, Rust doesn't have any real applications, because it's not out yet. The core team pretty much states, don't build anything significant in Rust atm.

It'll probably be out next year. Also Rust is a much more difficult language to grok, because it forces you to care about borrows.

Rust does have two major production deployments (OpenDNS and Skylight) and we've heard rumors of a few more. (Just this the other day: https://news.ycombinator.com/item?id=8743015 )

That said, yes, before 1.0, you have to be a special kind of person to do such a risky thing. That said, Skylight can't really do it another way.

>Yet remarkably people are solving real problems with Go. Despite all of these dire predictions and pontifications on here by so many mortally offended by Go's existence, people are simply making solutions and moving on.

Also people do that with C, C++, Python, etc etc, so no need to invent Go at all, right?

In addition to the points already brought up by sibling comments: Go is centred around automatic memory management. The downside to that is that Go might not ever be suited for certain domains: the upside is that automatic memory management is good enough for arguably most domains. Now, consider that many Go developers are coming from scripting languages; using Go gives them a lot of the performance boost, without also having to worry about the lifetime of their memory. And if they were using Python beforehand, chances are that implementing everything in C/C++/Rust instead won't really be necessary for them. Go gives good enough performance.

This overall comparison might be a dead end, though. After all, we're comparing languages that effectively only have in common that they seem to have been spawned at vaguely the same time. Their philosophies are totally different.

> Rust is a much better designed language which solves real problems

Well, so far it looks like Rust resolves real problems in theory. In practice, I just see much more projects made in Go than in Rust. I confess that I didn't go hunting for Rust projects though.

Maybe it's the same as Mercurial vs Git. The latter is more popular, even if it's "worse", according to some.

The comparison is unwarranted. Mercurial and Git were designed to solve the same problem (quite literally, even: both were conceived as an attempt to replace BitKeeper as the distributed version control system for the Linux kernel). Go and Rust were designed to solve very different problems. That people feel the need to constantly compare the two languages is because our industry is fad-driven, causing people to be ever on the lookout for The Next Big Thing lest they get left in the dust. This incessant veneration of novelty results in people who have only shallow understanding of a large number of technologies, leading to comparisons that are based only on superficial traits.
Reminds me of Hoare's quote on ALGOL 60: "Here is a language so far ahead of its time that it was not only an improvement on its predecessors but also on nearly all its successors."
yes absolutely agree. Go is better than plain C, but people aren't using it for things C is used for which I think makes a big difference.

When it comes to developing software applications, the really weak type system of Go is frankly just causing developer pain. IMHO, generics are the missing feature in this language, just try writing a generic map or reduce function in Go and the amount of code you have to duplicate is ridiculous. Interfaces and using relection is not safe and annoying and having all the XXXInt, XXXFloat, XXXMyType is crazyness too.

For what its worth, my dream language would be Julia's type system grafted onto Go.

I moved on, and stayed on my comfy JVM/.NET/C++ world, but won't have any issues using it if a customer asks for a project on it.
I moved on

This caught my eye because I recall you being someone who has vigorously criticized Go in every single Go discussion. A quick search and I can find lengthy critiques from you going back four years.

It very much seems like you haven't moved on.

I think he has moved on in the sense that he doesn't develop in Go anymore.
Given that he has been talking about how much Go sucks for almost the entirety of its existence, I highly doubt they've ever developed in Go. It became something to be an advocate against, not a tool in the belt.
I used Go before it went 1.0 and tried to contribute to os.user and some other experimental packages back in the early days.
I moved on in the sense that I am not arguing about it any longer.

If you read correctly my post, I just said I would like to see the discussion about generics take into account what other generic systems besides Java and C++ offer.

In those four years as you say, I have never seen such a document, even most discussions on gonuts went around Java, C++ and .NET implementations.

There are mentions that a prototype was made, yet the conclusions haven't been shared with the outside world.

If the designers don't want to implement generics, I can always look to Go as Active Oberon with C like syntax.

I see more value arguing about using Go for user space applications that are still made in C, just because the authors needed a compiled language than arguing about the essence of generics in Go. That boat has long left.

Edit: Just got to read Ian's opinion, quite interesting.

> my dream language would be Julia's type system grafted onto Go

With Julia's type system you get a really good parametric multiple dispatch, which is a completely different (and more satisfying, to me) way to organize code than in Go. Go wouldn't be Go at all with Julia's type system.

If that's what you want, why not just program in Julia?

I just want to point out that C actually supports generics in a form of pointer to void.
Casting to and from void pointers is very much not generics, and is in fact exactly what you have to do in Go (casting to and from `interface {}`) or pre-generics Java (casting to and from `Object`).

Although at least in Go and Java the downcast is checked and memory-safe, not so in C.

interface{}
I was responding to a comment claiming that Go is better than C in discussion about generic programming. I pointed out that C in fact supports generic programming (actually by void pointers and function pointers). Why you (and other downvoters) respond with the way to do it in Go isn't quite clear to me. I didn't claim anything about Go. I claimed something about C.
Maybe because Go's approach, although lacking, is still better than C in terms of type safety.

When you cast from void* to whatever type, the compiler will happily accept it and bad things will happen if the type is wrong. Maybe not right away, thus the program will bleed with corrupt memory.

With Go when you cast to the wrong type, a cast violation will occur and the program will panic right away.

I think that's memory-safety rather than type-safety: in Go (or Java or C#) the types may not be correct (so it's not type-safe) but it'll fault at runtime rather than possibly corrupt memory as C would.
From that point of view, at least interface{} is type safe.
You'd have been right if you had said "C actually supports generics thanks to #define", but `void*` is the equivalent of interface{}
> It is still better than just plain C.

But without the speed of C. D and Rust are both better than C and better than go, while still being as fast as C (ok rust isn't always as fast as C yet, but it is still faster than go).

This is a compiler issue, don't mistake language with implementation.

In fact, gccgo does produce better code than the *g compilers

It is partly a compiler issue, but the semantics of a language limits how fast of a compiler you can make. It doesn't really matter though, the fastest g compiler still produces slower binaries than any C compiler I can find.
So you are comparing a 5 year old compiler with 30 years of compiler optimizations?!

I remember the days when C code on home computers just sucked and most of us coded in Assembly for games, as C was a business language.

Compiler optimizations take time, even if sharing backends across languages.

>So you are comparing a 5 year old compiler with 30 years of compiler optimizations?!

No. You can clearly see that I am not doing that simply from reading my post. So, why the strawman?

More FUD and rationalizations from GhettoLang!

> do you want slow programmers, slow compilers and bloated binaries, or slow execution times?

Easy I want "slow compilers and bloated binaries".

In my experience "bloated binaries" in the real world aren't as bad as one would think, since instruction cache problems only appear when your working set is huge, not when your total binary size is huge.

Equating big binaries with slowness is simply misleading. What's next, increased download times?

> The generic structures are less useful than a concrete one.

Without generics you can't separate algorithms from data structures so everything is much less useful. If the members names are worse, sub-type then rename symbols.

> Generic structures can be less optimized than a concrete solution.

False. That "concrete solution" not only has to be written, but it will also perform identically to an instantiated template.

And type erasure is not a solution, it prevents inlining, constant folding and hoisting. Eg: In C++ std::vector<MyObject>::operator[] has 1 indirection, while using a generic C void* container would have 2. Guess which one is faster?

> Generic algorithms can be less optimized than a concrete solution.

sigh

Also wrong since generics do not prevent specialization if needed. See: static if in D, template specialization in C++.

> In my experience "bloated binaries" in the real world aren't as bad as one would think, since instruction cache problems only appear when your working set is huge, not when your total binary size is huge.

The "bloated binaries" part is especially odd given the state of the Go compiler's optimisations (or lack thereof):

    $ cat >| test.go            
    package main
    func main() {}
    ^C
    $ go build test.go          
    $ wc -c test                      
      467008 test
    $ cat >| test.go                  
    package main
    import "fmt"
    func main() { fmt.Println("Hello, World!"); }
    ^C
    $ go build test.go          
    $ wc -c test                      
     1806192 test
> Without generics you can't separate algorithms from data structures so everything is much less useful.

Generics is not the only way to separate data and algorithms. I agree that it is possible to sub-type/embed and rename - although looking at generic code, I rarely see that happen.

> That "concrete solution" not only has to be written, but it will also perform identically to an instantiated template.

When you know where exactly the code will be run, it can be possible to create a better package taking into account the context where it will be run. By concrete, I mean a package in a real-world problem.

Basically, abstract things are harder to optimize for a particular case.

> Generics is not the only way to separate data and algorithms.

Do you see any way other than the 3 ones discussed in the OP article under the label "Generics"?

> When you know where exactly the code will be run, it can be possible to create a better package taking into account the context where it will be run. By concrete, I mean a package in a real-world problem. Basically, abstract things are harder to optimize for a particular case.

I could agree with that if time wasn't limited, but imho building custom data structure/algorithms for each problem will precisely leave less time to optimize for performance since reaching a working state first will be longer without reusable abstractions.

> Do you see any way other than the 3 ones discussed in the OP article under the label "Generics"?

The one I mainly meant was interfaces. Of course there are also DSLs and code generation.

> I could agree with that if time wasn't limited, but imho building custom data structure/algorithms for each problem will precisely leave less time to optimize for performance since reaching a working state first will be longer without reusable abstractions.

I mentioned that in the summary. It's about tradeoffs. Even if all the cons/pros are listed people could still come to different conclusions, because people value different things. And there's nothing wrong about it.

The amount you need to reimplement depends on the amount of available third-party packages - the more good packages there are the less you need to build those custom data structures.

Let's just use the C++ approach. Maybe with more restrictions to prevent abuse. Maybe not. To me the problems with C++ templates arise from their verbosity (Go's type system is rigid, but defining types is easy and encouraged and the compiler does inference for variable declarations), their abuse (let's keep it to simple type insertion), and the nasty errors / debugging (Go's type system rigidity should also help here).

Just being able to do very light type insertion and the transparent code generation to go along with it would go a long way.

I was considering Go for some project of mine but the lack of generics turned me away because the project needed to do some heavy numeric computations over custom containers (sparse matrices).

Now days I think that adding generics to Go will be disaster - Go lacks sound type system and piling generics on top of it will make the thinks even worse.

In the pros for generic data-structures, it doesn't mention type-safety?!?!
Does anyone know how generics (for maps, slices, channels) are implemented currently in Go? Does it use type-specialization or boxing approach?
I find it amusing how angry people get about this, like really, vehemently angry.

If this issue is so important to people, don't use Go, use C++, Java, D or Rust. Don't waste your life arguing about something you'll never use, it's not a productive use of your time! Think about how much time you could save!

Alternatively, propose a solution to the problem and try and gain some traction to get it implemented into the language, or fork Go and implement it yourself. There's evidently a hunger out there for generics in Go, but everyone keeps assuming the responsibility lies with the Go Core team who's priorities seem (right now) to be in the optimising GC/compiler area.

This is exactly it. There are a lot of people who have argued passionately about this (the same crew of commentators appear with the same complaints in every single Go discussion), and now they are so deep in their advocacy that they feel their pride depends upon aggressively and vigorously defending it. It has gotten worse every time this has come up, and most of the comments are the logical conclusion. I mean seriously one of the comments calls it "ghettolang" without parody. Is this really Hacker News?

And exactly as you said -- for those people so offended by this: Move on. Use something different. Go isn't for you. As someone who has integrated Go very effectively into my life, I'm rather glad the Go team isn't listening to every railing fanatic and their pet issues.

>one of the comments calls it "ghettolang" without parody. Is this really Hacker News?

And then:

>I'm rather glad the Go team isn't listening to every railing fanatic and their pet issues.

Oh, the irony.

Why people assume that only people NOT using Go are complaining, it's beyond me.

Or why people assume that if you like features X of a product, and would like it to have feature Y, you shouldn't.

Nothing ironic about it. There are very vocal, very passionate people who pile the hate on Go in every single discussion regarding it. The list can usually be summarized as "ways that Go is not Haskell".

Which is strange, because a post about Haskell tends to be about Haskell. A post about Go tends to be a lot of people telling everyone how Go is unlike, to its detriment, other languages. Great -- go use those languages.

Why people assume that only people NOT using Go are complaining

HN doesn't have a large community of commentators, and you get to know the common personalities. There are absolutely people building solutions in Go who might think "it would be nice to have generics", and indeed that's exactly why they've never been discounted or denied by the Go team, simply deferred. But these discussions are dominated not by those people, but instead people telling you why Go is not Rust is not Haskell is not C# is not...

What's the point? We have a lot of languages and environments to choose from, and we do. Why are people seemingly threatened by Go? It's bizarre.

Generics are nice and they're important, but there are a lot of nice and important attributes to a language, and they have bigger priorities. If generics were critical to my work, I simply wouldn't use Go (and indeed, for some subsections and components, I don't for that reason. Life goes on. Different tools serve different needs).

> Why are people seemingly threatened by Go?

I don't think anyone's threatened by Go. I think some people are disappointed that Go's designers chose not to add a lot of extra type-related features, including generics, for some extra effort on the part of the language designers but very little cost (and much benefit) to the language users. If this was an unused toy language there would be no problem, but the existence of lots of code written in any language will have a small cost on other developers for social reasons, even if they don't use that language.

I don't think anyone's threatened by Go.

Yet your final sentence says exactly the opposite, indirectly. As if Go is some sort of scourge that these gallant guardians of language must fight.

Further, if you assess the simplicity of adding generics, and it is at odds with the actual people creating the language and tools (among whom are some of the most respected names in this industry), that's a point when you should stop and reassess your own, outsider-looking-in perspective.

> , and it is at odds with the actual people creating the language and tools (among whom are some of the most respected names in this industry)

I hope to one day experience a Go thread with no appeals to authority with regards to the language inventors/implementers.

I hope to one day see a thread with no misplaced logical fallacies.
(comment deleted)
What are you even trying to say?

The appeals to authority are not always used in a fallacious way (like the informal logical fallacy). But I don't personally like it, and I think it is intellectually lazy. It's better to let the product itself stand or fall on its own merit.

Your incantation of the logical fallacy is how it often appears in what could best be described as ignorant conversations.

The appeal to authority fallacy is if I measured the acidity in a lake over a long term period, and then presented my findings and someone declares that such can't be the case because the Environment Agency says it's fine. They're undermining my objective, demonstrated efforts with a hand waving appeal to someone else. If, on the other hand, I casually and lazily said "I think that there lake is acidic, no matter what anyone tells me", it isn't an appeal to authority to point out what someone who is undoubtedly in a better position thinks and actually knows.

In this case someone offhandedly, based upon nothing but the fact that they seem to want it to be true, declared the ease with which the Go team -- you know, the actual people working on it -- could add generics. No fuss, no muss. It isn't an appeal to authority to point out that they are in absolutely no position to make such a claim.

> Your incantation of the logical fallacy is how it often appears in what could best be described as ignorant conversations.

Like I said; I didn't mean that you, or necessarily people in general, use the appeal in a fallacious way. But it was my fault for not making that clear to begin with.

This is a general note, not thinking of any post or argument in particular: I can hardly count the number of times people who advocate Go will bring up the fact that people like Rob Pike and Ken Thompson are or have been involved in the project, and how smart they are and even 'how can I even question their work, given their skill and talent'.

>among whom are some of the most respected names in this industry

Most respected names in the programming industry.

Not in the language/compiler design industry.

>Which is strange, because a post about Haskell tends to be about Haskell. A post about Go tends to be a lot of people telling everyone how Go is unlike, to its detriment, other languages. Great -- go use those languages.

What you write above shows that HN users don't have the same behavior with other languages indiscriminately...

So, doesn't this sound like maybe it's Go that's problematic and not HN user behavior? (see also below)

>There are absolutely people building solutions in Go who might think "it would be nice to have generics", and indeed that's exactly why they've never been discounted or denied by the Go team, simply deferred. But these discussions are dominated not by those people, but instead people telling you why Go is not Rust is not Haskell is not C# is not...

And why shouldn't they? (Well we)

Go has design problems (beside the lack of Generics) the same way PHP has or JS has.

And it's criticized in a similar manner as when JS is brought up its type coercion is mentioned, or its global by default scope, its confusing this context, etc.

Now you might agree with the above or not. But what you ask is essentially for people that perceive it that way, to not speak, and just let it go.

Isn't the whole point of HN discussion (including about languages), criticism etc? It sure is not about celebrating all languages just because they exist...

I was thinking this exactly. As an external observer (I don't use go, don't intend to. I do look to it as an interesting example language though) all the vitriol is very puzzling.

And you're right, the Go core team does not seem interested in adding generics anytime soon.

Personally, and this is my opinion, I find myself wondering if old school hackers like Thompson, Pike, and Fitzpatrick (and others) find themselves not needing generics, or that slice/maps are enough, maybe I should ponder that for a while. Ie do they know something I don't? Edit; or maybe the type of software they're creating with go is different than I as a generics user, am creating?

>or maybe the type of software they're creating with go is different than I as a generics user, am creating?

Or maybe their work is mostly creating Go, not using it, so they wouldn't care?

It seems like the people who actually use it love it. The folks who don't are the ones raging that Go doesn't have generics, after all.
So should people stop talking about the pros/cons of programming languages at all? Because this can also go the other way. Another person can say: "If you enjoy programming in Go, then use it but keep quiet and stop promoting it and talking about how much you like it."

I haven't used Go at all yet, but I'm interested in hearing more about it the good and bad parts, along with other languages. Telling others to not complain at all doesn't do any favors.

I agree, but I think there's something to be said for not complaining about lack of generics in Go. We kinda got it the first 100 times it was said.
then use it but keep quiet and stop promoting it

Remarkably there has been close to zero promotion of Go on Hacker News. Occasionally various incremental update things appear on the front page, just as there are updates on C# 5, the next version of Java, etc, but there have been shockingly few "Why you should use Go" type posts.

People just use it. They don't advocate it. But when it comes up, inevitably it becomes an advocacy starting point for alternative languages. Somehow every single Go discussion, even about the most banal thing, ends up being about Rust, Haskell, F#, and so on.

Koolaid point. Go is a much, much worse language than e.g. D, Rust, OCaml, but somehow it gets all this attention. I appreciate it's not productive, but you can see why this naturally makes people angry.
Perhaps the reason for anger is because of Go ignoring years of research and innovation. I would imagine people who were early adopters of power tools felt the same way.

Imagine if you were used to using power tools, but all the jobs available forced you to use hammers, screwdrivers, etc. Wouldn't this make you a little angry or at the very least disappointed?

Sorry, but I can't see the value of posting this to hacker news. As evidenced by many people in this thread assuming it's from one of the core Go development team, it's not.
Exactly. This is one person's attempt to distill the previous conversations down to one document. It's not supposed to be justifying or rationalizing anything, nor does it speak for the core language contributors!

It's one person's summary of a very long and convoluted conversation. That's all.

Didn't intend for it to end up on HackerNews - at least not yet. It's still the first draft, most of it I wrote up in ~2hours. I made a mistake for not putting the "Draft" note at the top of the page in the first page.

I try my best to be objective - obviously this isn't easy. This is intended to be a review of both sides of the arguments. The generics discussion comes up again and again - I made this document to stop arguments going around in circles.

I will go over all the suggestions and add any missing information. Of course, if you have some good overview of some particular generics implementation you can PM me, or simply add that as a comment.

Given "go generate", I actually think that code generation might be better. It's a more fussy mechanism, yes - but it's also a lot more general.
1. Any old-timer Windows developer will tell you that statically generated code still has to be understood and maintained.

2. generics are about type-safety, not codegen. Codegen can be added on top of parametric polymorphism (e.g. C++ template specialisation), but is not required by any means (C# or Rust don't do any generic-based codegen beyond reification)

To be fair I've not worked much in a languages that support generics but I assure you there are type safe solutions to most every problem without them (as long as you don't write yourself into a corner). Whether my life could be simpler using them is unseen but to say the lack of them cripples a language is wholly untrue. You're simply used to using them in your solution and are wired to think with them. That's a flaw in the developer, a lack of imagination, not a flaw in the language. Arguing every language needs every feature every other language has is stupid. "[lang1] is bad because it isn't [lang2]" Is always an infuriatingly stupid and pointless argument. Use lang2 if you love it so much. Seriously.
That we can manually hack around this with busywork and tiptoe around the issue with various hacks doesn't mean it's not a flaw in the language.

It's 2014. Generics are a settled deal in programming languages. It's not some syntactic sugar or something the value of which is stull undecided and its advocates might "lack an imagination".

>Use lang2 if you love it so much. Seriously.

Well, some do. That doesn't mean they don't get to complain about something they perceive broken in Go that could be better. Especially if they could use Go (to take advantage of other benefits it might have) if it weren't for those shortcomings.

In general, the statement is analogous to "if you have a problem with X in america, why don't you immigrate", which is silly. If you have a problem, you criticize, and you try to change that. You don't just dismiss everything that's also not problematic.

The cons subsections that say that a generic version can be less optimized than a concrete version should mention which implementation is considered. If you use mono-morphization, then you end up with the same code as you would have written by hand, so there is no loss of performance there.
Abstract things are harder to optimize than concrete things. A package for a concrete problem can be more optimized than a generic/abstract package.

I don't mean that the manually specialized version is faster than automatically specialized template. Rather that this encourages to not write abstract data-types, but rather concrete types that solve a real world problem - editor.Buffer vs. gap.Buffer. Once you have a real world problem it can optimized much better for that use case.

As a language, I like Go. I would like it to have generics (Ada-style generic syntax might fit best). I don't care enough to get emotional about it. So, meh.
(The Java approach.) Box everything implicitly.

Boxing and generics are orthogonal concepts.

Also: does auto-boxing even make sense in Go? Between the fact that Go is statically compiled and that there isn't an int / java.lang.Integer dichotomy to resolve, I would assume that the compiler could just do whatever it needed to with primitives, regardless of generics.