Hacker News new | past | comments | ask | show | jobs | submit login
Generics aren't ready for Go (drewdevault.com)
70 points by kragniz 33 days ago | hide | past | web | favorite | 232 comments



This reads like sour grapes.

Basically, this is trying to spin "Popular language missing essential feature" into "But what if it's because they're braintstorming something EVEN BETTER???"

Well, if they're brainstorming something better, then I'll wait to use your language until you solve all the basic problems first.

Plus I think the language-obsession is usually cargo-culting and signaling. All good engineers I know use and enjoy several languages. The hipster/all-talk/buzzword engineers are the ones who insist on prototyping garbage in a new language every 6 weeks and dropping it entirely thereafter.


>Popular language missing essential feature

But is it an essential feature? I've written a lot of Go code and I'm perfectly fine without generics. It makes my code a lot simpler, no need to abstract everything into Thing<OtherThing implementing Stuff, YetOtherThing<Thingie implementing This or That>>. By the way, C doesn't have generics.

If you really need generics that badly for your use-case, nothing stops you from using another language.


Bringing up C invokes my suspicions about this debate: It's really people with totally different use cases talking past each other.

C doesn't have generics. Java has extremely limited generics. In both cases, it means that it's annoying and difficult for me to write a decent math library. I have to choose among making it support only one numeric type, implementing many copies by hand (one for each numeric type), or using some sort of ugly code generation tool - who knows what in Java, the preprocessor in C - to implement all those copies.

Which might not be a problem for everyone, but, for my use case, it's annoying.

(Deliberately avoiding the "generic library of data structures" use case because, while generics are what brought that to most of us (edit - in the world of static typing), it would appear that Go's handling that case just fine without them.)


I'd say either resort to code generation or pick another language that fits better your use-case.


Yeah, sorry if I wasn't being clear. That's pretty much the line I was thinking along.

It's perfectly fine for Go's answer to be, "Go doesn't have generics because generics aren't needed to solve the kinds of problems Go is designed for solving, and we are not trying to be a kitchen sink language here. If generics are something you need, please pick a language that's designed to solve the problems that you're trying to solve."

But that's a far cry from what TFA said. TFA read more to me as, "Go doesn't have generics because generic programming is a half-baked idea that isn't ready for prime time."


Or, to throw a third option one out there -- "Go doesn't have generics because they would interact poorly with some other aspect of the language." That works, too.

For example, it's why F# continues not to have ad-hoc polymorphism, despite many users clamoring for it. I'm inclined to agree with the project's maintainers on the subject. As useful a thing as it is, and as glaring as it is for a modern descendant of ML not to have it, it's hard to see how it could be added without creating all sorts of language warts.


Both F# and C# can do ad-hoc polymorphism - I use it in my language-ext library [1], the library is C# but the principle is the same for F#. It's not idiomatic (or pretty), but it's possible if needed. Higher-kinds is the killer missing feature.

[1] https://github.com/louthy/language-ext#ad-hoc-polymorphism


> I think Go should be comfortable not being suitable for writing certain classes of programs. I don’t think programming languages should compete with each other in an attempt to become the perfect solution to every problem. This is impossible, and attempts will just create a messy kitchen sink that solves every problem poorly.

is a quote from the article, and seems to say exactly what you're saying?


C does have generics since C11, although relatively constrained.


To me, despite the name, _Generic(...) doesn't really count. It's more like a switch statement that lets you switch on a type instead of a value. You still have to manually write all your own implementations, which leaves you firmly in territory covered by the 2nd option I listed.

Maybe I'm missing something, though. On the rare occasion that I write C code, I stick to C99, so I haven't had much occasion to use it.


If you nitpick enough, nothing is essential. We can write everything in C, or heck, even assembly.

"If you're not happy go look elsewhere" doesn't move the needle on the question "Should Go have generic" at all. It's not an argument at all.


Then should all languages have all features?

As the author explains in the article, I don't think all languages should try to solve all problems perfectly.


I don't see how that is the point I made. The point I made was that an argument should be given as to whether a feature should be in the language or not.

Note that this leaves the possibility that a feature should not be in the language, even if it does solve a real problem.

Both arguments do not address whether the language should have a feature or not.

"Not essential" might be recast as a valid argument, but must be rephrased in terms of cost vs benefits of the feature examined wrt the goals of the language.


Of course it isn't an essencial feature, all the older timers here had to code with programming languages without generics support for a couple of decades.

By the way, C has minimal generics support since C11.


I'm not super educated on this, but the example I'm asking is "How would you port the library lodash to your language without generics?"


"Porting lodash" isn't an end unto itself, but you can use `interface{}` everywhere and have the same degree of type safety that lodash enjoys, which is to say zero.


You can also use lodash with TypeScript, and get a great deal more safety than that...


Granted, but "lodash" is still a means and not an end.


> Well, if they're brainstorming something better, then I'll wait to use your language until you solve all the basic problems first.

Yet people can write distributed databases, monitoring tools, dns/DHCP servers in go. ANd they deliver stable and performant solutions with thousands of institutional users.

How come, if the basics are not solved?


That is a meaningless statement. You can do anything in (almost)any language that doesn't mean the basics are solved.


The parent should have said, "Go is regularly used to ship..." instead of "Go can be used...". The fact that Go backs all sorts of complex, interesting software testifies that it has solved the basics extrememly well, and if you're going to argue for a definition of "the basics" which doesn't respect shipping software then your argument is self-defeating. "Generics" isn't an end unto itself, after all.


> The parent should have said, "Go is regularly used to ship..."

So does C, C++, Java, etc. That statement is meaningless. It just means that with enough contortion, you can write some code in golang that works. But that doesn't mean mean there aren't better, safer ways to write code. As others said, you can write large systems in C, but we still see the fallouts of using a very limited and unsafe language.

And the funny things is, how do some of these larger projects get around golang's limititions? They write code generators to emulate mocking and generics, ending up with a weird mix of code that is difficult to manage. I saw this at my current employer, where they use golang for most of their backend. It's funny that I always think that even writing in Java would make the code base a lot more maintainable and even shorter and less verbose.


> So does C, C++, Java, etc. That statement is meaningless.

You're not following the conversation. The question is "Does Go solve 'the basics'?", not "Is Go better than C, C++, Java, etc?". I noted that Go solves 'the basics' for any meaningful definition of the term, as evidenced by regularly shipping useful software; I didn't claim that "regularly shipping useful software" makes it better than other languages.

> And the funny things is, how do some of these larger projects get around golang's limititions? They write code generators to emulate mocking and generics, ending up with a weird mix of code that is difficult to manage. I saw this at my current employer, where they use golang for most of their backend. It's funny that I always think that even writing in Java would make the code base a lot more maintainable and even shorter and less verbose.

This is a fallacy. A code generator is a pain in the ass to work around generics, but it's entirely possible and likely that the efficiencies gained by Go (versus Java or other candidate languages) more than justify the losses due to a code generator compared.

It's also entirely possible and likely that people are throwing code generators at problems (like mocking) that don't require or benefit from code generators.


> So does C, C++, Java, etc. That statement is meaningless. It just means that with enough contortion, you can write some code in golang that works.

Indeed it's as capable as those languages in this domain. The productivity is higher though, thanks to the stdlib.


Go's stdlib is a tiny portion of what Java and .NET offer.


Yes those are two bloated stdlibs.


On the contrary, they are feature rich with capabilities that Go still hasn't found a proper way to support, like something comparable to Swing.

Naturally turning into name calling is easier when running out of arguments.


Java hasn't found a proper way to support something comparable to Swing. :)

If Java's standard library is reasonably sized, what is your idea of a bloated standard library? How often do you use SOAP? Applets? Open MBean? CORBA? Relation?

> Naturally turning into name calling is easier when running out of arguments.

I like many of your posts. This one is just gratuitous ad hominem.


You say this as if swing is a plus for java. It looks alien everywhere. Is it used by eclipse by the way?


It is used by JetBrains products, a fairly small company selling developer tools, you might have heard you them.

They happen to sell an IDE for Go.


They did pop up in short period of time and go projects are generally considered quite stable - how can you achieve those without "basics being solved"? IMHO basics is precisely what they did solve exceptionally well.


I used to write full blown applications in Assembly as well.


With thousands of institutional users? Implementing distributed databases?


As much as old time mainframes and Novell NetWare based applications could have.


Then it was the proper choice, like go is today. I haven't heard about a lot of distributed databases in assembly.


Most successful distributed databases taking load at scale with powerful OLAP engines are written in C++, not Go.


Indeed. However go does make some inroads there for oltp workloads or simple kv like etcd.


Not with anything comparable to ScyllaDB, RavenDB, Akka, Akka.NET, Orleans.


Nobody uses ravendb or akka.


Everyone here would like some numbers, after all you must have a solid source to make such statement.


Care to provide the name of VC backed companies built around them? I do not know of any. Akka has some java shops using them. But I wouldn't call it a database.

Ravendb...


You got me lost there, first you say nobody uses them, then you mention some.

Better get those numbers straight.


You're being ungenerous. The way they are using "basics" implies that they don't have the basics they expect to have for the problems they want to solve. The fact that someone else has the ability to solve other problems using the tool is irrelevant, and only highlights that you have different expectations.


Lack of generics is a feature imo


> Go strikes me as one of the most conservative programming languages available today. It’s small and simple, and every detail is carefully thought out.

This article is wrong in many ways, but I thought I'd point out this particular one. There are many really weird warts in Go, in fact its about average in "wartiness". Here is one example https://dave.cheney.net/2017/08/09/typed-nils-in-go-2

Go biggest advantage isn't the language, its the decent documentation and standard library design. The language is a bit mediocre. I wish the Go community accepted this and moved on - a mediocre language with good documentation and well done standard library is still an acceptable contender since so many other languages get those two wrong.


There are some weird parts in the Go language, yes. But since it's so small, a lot fewer than other languages.


> Go biggest advantage isn't the language, its the decent documentation and standard library design

Which, ironically, Java is just superior in every way when it comes to documentation of the standard library. Large open source Java projects are well designed and very well documented, unlike golang projects.


Java is not really superior in standard library design. There is too much architecture astronautics going on. Standard interfaces are too complicated. Nominal interfaces kinda suck. Java also lacks green threads. There is baggage in the design of many libraries related to previous lack of lambdas that is now annoying.

The Go documentation as well as standard interfaces are tastefully and minimally done (for an imperative language): https://golang.org/doc/ - e.g. https://golang.org/pkg/io/ ... To my knowledge there is no equivalent of this for Java that comes close.

Compare https://golang.org/pkg/io/#Reader to this mess https://docs.oracle.com/javase/7/docs/api/java/io/Reader.htm...

Java has pretty nice generics. With Java 10 the language is now decent too.


> Java also lacks green threads

Green threads are not the be-all-end-all solution for concurrency. They have their place, but so do event based async io.

That being said, Java is getting green threads in the form of Fibers.

> Compare https://golang.org/pkg/io/#Reader to this mess https://docs.oracle.com/javase/7/docs/api/java/io/Reader.htm....

Obviously Java's Reader interface does more work, and has a `close()` method, which golang lacks. Golang is forced to go with this way to write interfaces due to how they are implemented (sacrificing usability to get nominal typing, which is a very questionable design decision). Languages like Kotlin, Rust, Scala among others have superior solutions.


Can Quasar fibers be efficiently used with other (popular) Java libraries that build on top of the standard libraries? If not, I don't consider that to be good developer experience. That is more of a mistake that cannot be rectified.

Async IO is also fine. The question is, what is your current ecosystem built on top of. AFAIK the answer with Java is definitely not async IO or fibers.

Yes, structural interfaces in Go are implemented poorly. But the standard library uses them very tastefully, putting most standard libraries to shame :) Go also has Closer, and its a separate interface - interfaces are minimal which makes them much easier to implement and more generally applicable.


From Loom talks it appears that fibers will also be able to consume Runnable and Completable.


Loom is still WIP. Remains to be seen how easy / performant it is going to be adopt in practice with the existing ecosystem.


> Java also lacks green threads.

So weird. Java used to only have green threads. The very name, "green threads", comes from the fact that's what the JVM called them. Literally invented the name.


Too bad they were removed. I don't see why a non-system language should use anything other than green threads nowadays.


Because Java also runs bare metal and in those scenarios, it is indeed a systems language.

The HN community is too focused on OpenJDK/Oracle when talking about Java, when there are as several JDKs toolchains across the industry, some with very specialized deployment scenarios.


The lesson from that being, the extreme of "write once run anywhere" is not necessarily a good idea. Sometimes its best to implement specialized libraries and runtime (green threads) for specialized environments (servers) that are not available in others.


I'm under the impression that Java implements generics via type erasure.


Thats not an entirely bad way to do it.


Sucks for you, considered very good by plenty of other people who use it daily.


I use Go daily and I agree with the general sentiment that it's a janky language full of warts and could really benefit from features like generics.


Maybe go back to java or c++? I'd rather have less people complain about a feature I don't want in the language.


Just curious: why don't you want generics in Go?

The language already uses them for Arrays, Maps and Slices, plus a lot of code relies on runtime-typed ad-hoc generics with interface{}.

It's not as if Go is a language without warts... there's a lot of ugly stuff, like Iota, Reflection, the error handling, interface{} itself.

This is a legitimate question, btw. Legitimately looking for other points of view


Keep in mind that many golang programmers just parrot what the golang authors say, without fully understanding it or even realizing the golang authors are wrong (not saying that's the case in this specific instance).

They hear the golang authors complain about Java, that it's the only way to do things, so they think that the only other solution is to go the extreme opposite way, not even looking at real modern languages (which golang isn't) like Kotlin or even C# for instance.

It's very evident that the golang authors have no experience designing language, and didn't look in depth at what other languages did.


Unfortunately I am not parroting. If you are used to read code, and you read c++, you will see that templates are abused. No generics force devs to make their code clearer and thus more secure.

It is evident that Go is a better language than most thanks to the creators having deep experience in that domain.


for sure i can abuse Go's language features as well in unintended ways.

Language abuse happens when the feature is the only available feature to implemented a particular and no other language feature allows for a better implementation.

in C++ most abuses of template are related to the missing feature "concepts". which took quite a while to get their.

If language switching is not an option, and your application requires generics and you are also required to use Go, you do have a problem. You need abuse the language and work around re-implement generics for Go.

Which can result in a very ugly development process, difficult to maintain code etc.


They aren't abused in C#, Java, Haskell, OCaml and other languages. Honestly, picking C++ as an example of traditional generic usage is a bit disingenuous.


I think generics in C# are really well executed and solve a lot of problems in C#'s problem domain.

I do think you're on the right track that go's designers are pushing back hard on what they see as feature abuse in C++ and Java. C++ abuses templates and has dozens of ways to do anything that also don't interact with each other well. Java abuses inheritance, abstractions, and OOP.

go uses generics under the hood, probably the designers fear that generic's will also get abused if released into the wild. On the other hand I've never heard anyone bitch about well designed generics in other languages. Which is a tell since people will bitch about anything and everything.


> I do think you're on the right track that go's designers are pushing back hard on what they see as feature abuse in C++ and Java

Now that you mention it, I can't really blame them!

> On the other hand I've never heard anyone bitch about well designed generics in other languages. Which is a tell since people will bitch about anything and everything.

That's my opinion as well. Generics are quite pleasant, simple and a great tool to have when they're well designed.


I would suggest a Go programmer give ReasonML an honest try (as an example language where "generics" are done right), but the getting started / documentation situation is still not at Golang level so thats a bit annoying.

Maybe F# would be a better choice. .NET Core and its tooling are pretty well done. C# and NET Core would be another nice alternative.


Agreed. I find C# and F# surprisingly refreshing. ReasonML is a bit unfinished, but it's a sign of great things to come.


golang authors seem to only have experience with C++ as they keep talking about C++'s deficiencies, as if it's the only other language that exists when it comes to generics.


Sure. Seems like they have the same experience than me then.


The point is that they are not familiar with the solutions other languages have. So it's either the C++ way or don't look elsewhere.


Because they are easily abused (look at c++) and makes code unreadable. Working around generics usually make the code clearer and thus more secure


Go has interface{}, which can be abused as much as generics for the same purpose, but without the type safety, hence, less secure.

And nobody is advocating C++ style template metaprogramming. There are much better implementations of generics, as acknowledged by Russ Cox himself.


Usually interface{} is abused by java programmers. I agree that it's not great, but if you don't come from java or c++ chances you won't follow these patterns at least.


I'd love to get away from Go again, but unfortunately it's the hot thing that people see on your resume and then they don't want to talk to you about anything else. I'm very concerned that in a few years it's going to be the terrible low-paying boring thing that people see on your resume and don't want to talk to you about anything else.


Its the hot thing for a reason. Adapt or be left out.


I've been using Go in production for 5 years now, I don't think there's a lot of adapting left to do. From the other side of a few years of experience I think I see the reality of the situation pretty clearly. Go isn't a good language by any means. It's the hot thing because it's a marginally less painful blub than python or java and cheap entry-level developers can be onboarded to it quickly and be left to churn out boring but largely unharmful code. On top of it's programming with mittens mentality it had the force multiplier effect of becoming the devops language dejure. I think the staying power of Go is largely dependent on whether or not the industry finds the current state of devops a local maxima that it sticks on for a while, or whether things push further into PaaS territory and the current devops tooling becomes irrelevant for everyone except the big cloud platform implementers.


Same


There are plenty of people who consider C++ good too and its used by people daily. Doesn't mean that Rust isn't a better language, even though there are less people that use it daily.

I think we need to be real about what are the strengths and weaknesses of each platform instead of drinking the coolaid. Otherwise we don't learn anything and the bad parts are going to find their way in the next one.


It’s weird seeing all this post-hoc rationalising when there is a perfect explanation for why go doesn’t have generics:

Rob Pike didn’t bother to look into any of the research into type theory and programming language technology. Hence his understanding of types were restricted to Java and C++ and similar (whose type systems are an abomination), and he could not separate subclass polymorhism with inhertance from parametric polymorhism.

    But more important, what it says is that types are the way to lift that burden. Types. Not polymorphic functions or language primitives or helpers of other kinds, but types.
    That's the detail that sticks with me.

    Programmers who come to Go from C++ and Java miss the idea of programming with types, particularly inheritance and subclassing and all that. Perhaps I'm a philistine about types but I've never found that model particularly expressive.

    My late friend Alain Fournier once told me that he considered the lowest form of academic work to be taxonomy. And you know what? Type hierarchies are just that.
https://commandcenter.blogspot.com/2012/06/less-is-exponenti...

I mean he’s openly contemptous of the academics who do research in his field, while wildly mistepresenting their work. But people eat that shit up, because ”OMG it’s Rob Pike” instead of actually discussing the underlying issues.

Yes Rob, you are a philistine when it comes to types.. (or at least were)


Or maybe the academics and type theorists are philistines about the software that runs the world and their arguments have mostly been about hand-picked toy examples?

Maybe Mr. Pike actually has some well-deserved reputation when it comes to real-world software and engineering projects that are about handling large scale data in real time?


His well-deserved reputation makes me interested in listening to what he has to say, but you have to evalute anyone’s idea on its own merits.

I think there is a tendency to create an unneccessary barrier between ”real-world” software and ”useless” academic theory. I’ve spent most of my career working with java, php, python and js, and I absolutely agree with Rob that class hierarchies and inheritance is a bad way to program, but there’s a lot more to types than oop type systems with limited type inference.

It’s of course always a trade off, which is why I build frontends in Elm, backends in Haskell and play with proofs in Agda, but why throw away types altogether?


>about the software that runs the world

Software that runs the world utilizes parametric polymorphysm in C++, Java, Ada, D, Swift, OCaml, Haskell etc, hell, even C [1].

I also tend to consider some mission critical Ada/C++ software a real engineering, not some webshit.

[1] https://github.com/jiixyj/libebur128/blob/master/ebur128/ebu...


And [1] actually makes a point that we don't need language support for every imaginable use case (maybe not even Generics). It's not a problem to work around a "missing" feature, sometimes.


So, we would seem to have two key statements being pitted against each other here:

  1. Rob Pike doesn't have a strong grasp of type theory.
  2. Rob Pike is an accomplished programmer.

To me, this conflict of opinions is structurally indistinguishable from

  1. That shape over there is a square.
  2. That shape over there is blue.

IOW, there is no argument to see here.


No the two conflicting statements are.

1. Go doesn't have generics because the authors didn't have strong grasp of type theory.

2. Go doesn't have generics, not from a lack of knowledge, but because the authors' real world software engineering experience had shown to them it wasn't important.


Yeah, the second statement is also valid, though definitely not what I got from the parent's comment.

Though, in that case, I think the argument is more like:

  1. That shape is equilateral
  2. That shape is equiangular
It turns out it's a square. Rob Pike's public comments on the subject do seem to betray a weak grasp of actual type theory. Or at least one that is about as strong as it could ever get if your knowledge is primarily informed by practical experience with C++ or Java-style deeply broken type systems. But it's also true that Go's found an alternative approach that gets the job done. Or at least, gets the job done if you're writing the types of programs that he's writing.

So, even with the alternative statement, I still see no argument here.


I am not Rob Pike and therefore cannot provide proof of his grasp of type theory. But I also don't understand the desire to question and debate the knowledge of someone I've never met and has no influence on my life.

I have used Go extensively and would disagree with the idea that the lack of generics in go was ill-informed (and therefore a mistake). I find that Go's limited number of features leads to simpler libraries that are much easier to comprehend and use effectively. And in situations where I previously would have reached for generics I am forced to find a different approach and the end result is often better. Yes it does have its drawbacks and is not a perfect solution, but as far as engineering decisions go, I feel it was a successful one.


>Go doesn't have generics, not from a lack of knowledge, but because the authors' real world software engineering experience had shown to them it wasn't important.

What do you mean by "real world software engineering experience", Acme or Plan9? These are silly academic projects with tens of installations at best.


If your only metric is installations I'd say go is doing quite well at least.


Ken Thompson was one of the original authors of Unix


We are discussing Pike's profound engineering experience which constitutes the background of his bold claims about language design.


So really this isn’t a discussion about the design of Go (of which Ken Thompson was a part of) but just a chance to trash on someone you don’t like.


Well that was what I was trying to say anyway. Thanks for clarifying!


> Maybe Mr. Pike actually has some well-deserved reputation when it comes to real-world software and engineering projects that are about handling large scale data in real time?

What are the credentials to back this up? Otherwise, the languages he makes fun of actually are used to deliver large scale systems in real time. Google is built on C++ and Java, so are most of the other top tech companies, not to mention banks and HFT firms.


He is one of the Unix figures at Bell Labs (although a late-joiner, being younger), he designed UTF-8 with Ken Thompson, and worked on the Plan 9 project, before joining Google. That's probably more than most of us will ever achieve.


Plan9 didn't go anywhere. So other than UTF-8, there's not much to speak of. He's not a reference on programming language design, and it shows.

Compare to Leslie Lamport for instance, and the tremendous effect he had on large scale systems and software engineering correctness.


Can you argue your case as well as he does? https://www.youtube.com/watch?v=cQ7STILAS0M

Or are you just being disrespectful?


I read the slides, but didn't hear the talk. There is so much conjecture in them. C++ is successful, Java is successful, so are Python, C#, and a whole bunch of other languages.

When it comes to complexity, large systems tend to be complex, so you either push some of that complexity into your language, to give you expressiveness and modeling capability, or you simplify your language so much (golang) such that the code base becomes complex and verbose due to repetition, not to mention error prone.

Readability? Compare:

    var a int
    if foo() {
      a = bar()
    } else {
      a = baz()
    }
to

    final int a = foo() ? bar() : baz()
or even

    val a = if foo() { bar() } else { baz() }
the latter two are shorter by a factor of 6, clearer, and less error prone. This is a feature that both improves readability, and reduces complexity.

The funny thing is, the golang code bases I worked with would be quite a bit shorter in a supposedly verbose language like Java, not to mention something like Kotlin.

Do you want a practical reason why golang is popular? Because it has Google behind its name. The language that he worked on before he was at Google, which were similar to golang, went nowhere.


There's a name for what you're doing. It's called "cherry picking". And also there's a name for the act of pulling something out of context to support an arbitrary point.

Let it be said that I'm not actually a Go but a C programmer, and there might be about 1 legitimate use of this syntactic construct per few thousand lines in my code (you are free to checkout my language project from github and verify my claim). It's not that I don't know the construct, but more that most experiments with it end up being reverted again to the longer form, to preserve the rhyme and rhythm of my code.

I won't take sides, but I guess their idea was that like so many other features, this little syntactic sugar construct does not carry its own weight.

> I read the slides, but didn't hear the talk

You absolutely should hear it! The slides probably do not contain actual experience reports, opinions, and arguments.

> the golang code bases I worked with would be quite a bit shorter in a supposedly verbose language like Java

that's hard to believe. Any code samples for illustration? (I invite you to cherry pick!).


> There's a name for what you're doing. It's called "cherry picking". And also there's a name for the act of pulling something out of context to support an arbitrary point.

There's also something called "argument from fallacy". Either refute the points I raised, otherwise there's no point bringing up fallacies :)

> Let it be said that I'm not actually a Go but a C programmer,

I have been using golang at my current employer for several months now. That being said, that's your experience, and it doesn't necessarily mean that everyone else has your use case.

The shorter form is (1) more readable, and (2) less error prone - fact. Less code also means less room to make errors. It was pretty laughable on the golang mailing list when someone asked why there wasn't a max/min implementation for all number types in golang, someone replied why do you need it? You can just implement it yourself like so, and proceeded to write a max implementation where the comparison operator was flipped. It's quite ironic really.

> but I guess their idea was that like so many other features, this little syntactic sugar construct does not carry its own weight.

It does, it reduces the probability of error by making sure that assignment happens only once. They weigh things very arbitrarily, like how one of the golang authors doesn't think compile checked enums are worth it because hey, they're just enums checked by the compiler to ensure coverage. It shows they don't have experience with other languages, or with features that reduce error rates.

> that's hard to believe. Any code samples for illustration? (I invite you to cherry pick!).

I already listed the lack of a ternary operator or its equivalent, and this extends to other constructs which can be expressions. Java is getting switch expressions in the upcoming release, and in Kotlin, try/catch is an expression, it's quite nice. The most obvious other one is error handling, "if err != nil" checks everywhere, which makes the code base much longer.

Others include the lack of map/fold/etc functions. The code base I work with is littered all over the place with functions to do what effectively are maps or maps+filters. Those functions end up being 8 lines or so, whereas they could be fit in 1-2 lines, inline at the call site, without the reader having to jump to the function implementation. This gets tiring very quickly, and makes it take longer to understand the code at hand.

Another example is needing to explicitly assign to a temporary variable if you need to take its address to pass it as an argument.

    a := foo()
    b := bar()
    c := baz()
    qux(&a, &b, &c)
as opposed to for example Rust:

    qux(&foo(), &bar(), &baz());
or Java

    qux(foo(), bar(), baz());


[flagged]


You're being disrespectful.

> No mission-critical software, no application software with millions of installations (except Go compilers).

Yes. NOOO software with millions of installations. Except Go compilers. Which doesn't count? (And I don't even know, there might be more).

He is an accomplished engineer. UTF-8 is one of the best designs I know. Unix is still around, despite its shortcomings. He's written books and been around some of the gods of software and OS engineering. Regarding Plan 9, I'm not positive that it is a toy operating system. I've never used it. It tried to improve on Unix and might (or might not) have achieved that in many ways. It's named as an inspiration by Linus Torvalds.

What do you have to show?


I read what you linked. No, he is not "openly contemptuous of the academics who do research in his field, while wildly mistepresenting their work" (at least not in the linked article). It would be more fair to say that he doesn't think that, in the real world, types will carry enough weight to deserve the emphasis that they are given.


As a physicist I find out of context references to physics pretty annoying. No go modules are not like a grand unified theory, nor is any other go package management solution like general relativity.


Just enjoy that these kinds of references give you so much latitude for interpretation.

For example, in the absence of any practical exposition demonstrating that the module system solves problems that other systems don't, you can quite comfortably (and cynically, sure, but please let me have my fun) choose to interpret the analogy along these lines: General relativity is well-established, reasonably well-understood, and is essential to making a sizable chunk of the modern world (e.g., GPS) work. Whereas nobody's been able to demonstrate a working GUT yet, so currently its main practical use is as fodder for books and TV specials.


> The constraints imposed by the lack of generics (and other things Go lacks) breed creativity

Uhg such programming language Stockholm syndrome. You could apply this fallacy to any feature. The lack of modules and a performant garbage collector also bred creative solutions in previous Go releases, but that doesn't mean that adding those was a bad idea.


As said in the article, solutions to these problems have now been implemented. These solutions _feel_ very Go-ish. Modules are an elegant solution. Adding them was a good idea.

Until we find an elegant solution for the generics issue, it's better not to have them.


Maybe a Go programmer can enlighten me - without generics, how can you have data structures implementations that can contain more than one type? Do you have to have one linked list implementation for every type in your program? Do you have to abandon type checking by using an equivalent of void pointers? Or is the type system smart enough that you'd never need generics in the first place?


Yeah, you have to either give up type safety (Go's "void pointers" retain runtime type information, so it's closer to a Python object than a void pointer) or you have to write each implementation. In the case of linked list, that's not a big deal: `type List struct { Next *List; Value int}` and Go comes with a handful of useful generic types (slices, arrays, maps, channels, etc). It also has interfaces and closures, so you can generally go a long way without generics.

That said, there are still cases where generics would be useful; however, a lot of the people who complain about generics missing from Go tend to exaggerate the extent to which this is a problem, "You can't ship software in a language without generics!". In the case of Go, you have something like 97% type safe code compared to the many, many successful Python and JavaScript programs that ship with 0% type safety. And lastly, one thing that you can't really appreciate without trying Go--the lack of generics/expressiveness and general simplicity of the language largely means everyone writes the same boring, predictable code, which means you can pretty much pick up any project on GitHub or your own code from years ago and understand it almost immediately. This isn't to say that generics aren't worth it; only that the debate kind of sucks because one side is ignoring that rather significant point.


> "You can't ship software in a language without generics!"

Isn't this is a strawman? Most arguments in favor of generics in this thread and elsewhere are well informed and people just want safer code...

As you said, you can already have generics using unsafe solutions. Some built-in types have generics. Most people just want this type safety.

interface{} does feel like a temporary and clunky solution for people used to generics.

> And lastly, one thing that you can't really appreciate without trying Go--the lack of generics/expressiveness and general simplicity of the language largely means everyone writes the same boring, predictable code, which means you can pretty much pick up any project on GitHub or your own code from years ago and understand it almost immediately.

I don't get this argument. Why are generics more complicated than other features? Has this hypothesis been tested?

I personally find that using generics is way easier and faster than interface{}, Reflection or code generation. Also simpler and less error-prone than features from other languages like inheritance, operator overloading and unbounded coroutines.


People always go on about type safety, but in practice it normally doesn't matter. I have an instance of a data structure; I put in items of type Foo; I remove items of type interface{} and immediately cast them to type Foo, and life goes on. Sometimes, I might need to put in items of different types, and then I use a type switch. It's not a big deal, nothing panics, I get on with my life.

Yes, there's a class of programs for which this is not the case, and for which I might want some sort of fancier guarantees. But those don't tend to be the sort of programs I write. My hobby projects are in Common Lisp; I used to professionally program in Python and JavaScript (for my sins) — Go is strictly better than those in the static-typing department.

Would I like generics? Sure, I can see how they'd be nice. But I remember how templates in C++ turned into something nasty, and I've written Java professionally too: I like how clean & simple Go is. I can write code, then be done with it, and come back a year or two later and not be mystified. It's a decent little language for getting stuff done.


You should read the typescript threads, where people want types to make their code more bug free.


> Isn't this is a strawman? Most arguments in favor of generics in this thread and elsewhere are well informed and people just want safer code... > As you said, you can already have generics using unsafe solutions. Some built-in types have generics. Most people just want this type safety. > interface{} does feel like a temporary and clunky solution for people used to generics.

It's not a strawman; I run into this tired argument too often, so I wanted to call it out to avoid the predictable digression. There is a strong case for generics and I empathize with "`interface{}` is clunky..."; I just want a debate that recognizes the tradeoffs.

> I don't get this argument. Why are generics more complicated than other features? Has this hypothesis been tested?

I don't think I made the argument that "generics are more complicated than other features". My argument was that Go code is boring and predictable (consistent). It stands to reason that boring, consistent code is easier to read and understand than novel and/or mixed-paradigm code. Generics increase expressiveness, which pretty much by definition means fewer rails to keep code consistent. I'm not arguing that Go's current feature set strikes an optimal balance between expressiveness and consistency for all problems; however, it does do a pretty good job and we should count the costs as well as the gains when considering a new feature.


I personally find most implementations of generics to be in the class of "boring and predictable".

I agree that C++ template meta programming might be a bit too much for Go (or for any language, for that matter), but generics as they are implemented in C# and Java are pretty cool and simple.

IMO, if generics were to be ever added in Go they should just be a simple replacement for some uses of interface{} and code generation. I mean, the complexity is already there... why wouldn't generics simplify those use cases?


I'm talking about code written in Go, not the implementation of any particular feature. Generics would simplify those cases, but they also remove the rails that keeps Go code pretty consistent relative to Java or C#.

For example, in Go, there is no functional-vs-imperative conundrum; it's only imperative. And I appreciate that there are multi-paradigm languages like C# and Java that allow for both (better for experimenting with new patterns and paradigms); however, I also appreciate that there are languages like Go that take a more conservative opinion, and I think this is more practical for software development.


> they also remove the rails that keeps Go code pretty consistent

But why? There's nothing in generics that would make Go non-consistent. In fact, there's already generics in Go in Array/Map/Slice, and they're not inconsistent with the rest of the language at all.

> For example, in Go, there is no functional-vs-imperative conundrum; it's only imperative

Why would generics break that? Funcional programming and type-safety/polymorphism are orthogonal concepts. IIRC, generics were introduced in Barbara Liskov's CLU language, which is imperative.

It sounds to me that most people advocating generics in Go are having a pragmatic/utilitarian approach, while people against it are opposing it from a purely ideological standpoint not grounded in either theory or pragmatism.


> It sounds to me that most people advocating generics in Go are having a pragmatic/utilitarian approach, while people against it are opposing it from a purely ideological standpoint not grounded in either theory or pragmatism.

And it sounds to me like you're working rather hard to misunderstand me/my-opinion and paint me an idealogue. :)

Even if I were making a positive assertion like "generics costs more than it gains", that would be a pragmatic viewpoint even if it's incorrect. But I'm not even making that assertion, I'm merely unsure and would like to be persuaded otherwise (and I find people with experience on both sides of the fence to be more credible than those without that experience).

> Why would generics break that?

Because "generics" as a feature suffices to support multi-paradigm programming. It explodes the solution space, creating many solutions for problems that Go's type system is perfectly capable of dealing with (~97% of the problem space in practice according to my experience) while permitting new solutions that Go's type system must currently punt on (~3%). We should be able to roughly agree on this even if we disagree about the degree to which multiple solutions is a problem relative to the advantage of the additional type safety.


> And it sounds to me like you're working rather hard to misunderstand me/my-opinion and paint me an idealogue. :)

That's fair! I'm really sorry I typed that, it was completely uncalled for and I wasn't referring to you specifically!

> Because "generics" as a feature suffices to support multi-paradigm programming.

I don't really agree with that. Despite being widely used in functional languages, they aren't really a "functional" thing, as much as static typing is.

In fact, I'd argue that Go already has a feature that is much more important and representative of funcional programming than anything else: higher order functions. [1] With higher order functions (and recursion!) you can implement pretty much anything functional.

Generics don't really allow for much more than something like interface{} can already give. The problem is that interface{} comes with both runtime performance and type-safety penalties. Generics could fix that and help programmers arrive at better/safer practices, IMO.

My point is: with generics the language could be much simpler and we'd have to rely less on (IMO) complicated/unsafe features like Reflection and interface{}.

[1] http://aquaraga.github.io/functional-programming/golang/2016...


On a phone, so sorry in advance for terse response. Agreed that the language would be simpler in some sense with generics; I don’t think it would be more readable due to aforementioned increase in expressivity. Interesting point about first class functions, and while I largely agree, the variation in Go code is still small and constrained which is my point. :)


You don't find the existing Go code using the built-in generics (arrays, dictionaries, channels) readable? You find that its expressiveness makes it too complex?


Sorry if I haven’t articulated my position very well: the property I care about is consistency of code throughout the ecosystem which exist due to the constraints such as the absense of user-defined generics. Hopefully that’s a little clearer, and makes it obvious why “a few built in genetics” is fundamentally different than user-defines generics.


Go use a duck typing system, many of the generic use case can be solved using interface elegantly..

For the rest... Yes, it is very ugly. But the standard generic does not fit very well with go type system, so....

Luckily, go is very simple. Even ugly bit are not hard to understand.


> But the standard generic does not fit very well with go type system, so....

Why not? Generics in Arrays/Maps/Slices fit perfectly in the language, and don't feel weird at all in Go.


> Arrays/Maps/Slices

They are widely used data structures and so, in the opinion of the Go creators, justified separate specialized implementations in the Go compiler. In other words, there isn't actually a Generics system in the language (I don't actually know this, correct me if I'm wrong). For various reasons. There are quite a few talks and design docs from Rob Pike and Russ Cox if you look for them.


Nope. They are generics, aka parametric polymorphism. And they fit perfectly within Go.

And generics aren't just for abstract data structures, there are other uses as well.


I think you've misunderstood what I said. For example here: https://golang.org/src/go/parser/parser.go you can clearly see how e.g. token.MAP is a special case.

    func (p *parser) tryIdentOrType() ast.Expr {
        ....
        case token.MAP:
            return p.parseMapType()
There is a special-cased function parseMapType() function in the Go parser. This isn't generic at all. I mean even the syntax (as in func foo(bar map[String]int) ...) does not seem to be generic at all.

Yes, you can use any type as keys and values. But that's a far cry from an abstract system that lets the user define any parameterizable data type. And that's for good reason: By hardcoding just the most important parameterizable data types, the problems that an abstract system would bring can be avoided.


Yes, I'm aware that they're a special case. What I mean is that this is exactly what is traditionally called "generics" or "parametric polymorphism" in PL literature. Go's Map/Array/Slice called "predefined generic types" in some literature.


> Isn't this is a strawman? Most arguments in favor of generics in this thread and elsewhere are well informed and people just want safer code...

As a C programmer (which doesn't have generics either) I can't recall the last time where that additional safety was being missed. Whenever I fed the wrong argument in for a void* parameter (which is rare enough), the program crashed on the first try and the problem is obvious. Plus, Go even has runtime type checking to catch this sort of problem with 100% probability at runtime (I think - I'm not a Go programmer).

So I don't think there's a valid problem here.

Maybe the more serious problem is that people want to be able to quickly say "I want a Fibonacci-Tree<K,V> for types K and V"?


> Whenever I fed the wrong argument in for a void* parameter (which is rare enough), the program crashed on the first try and the problem is obvious.

Except when it isn't. Except when it crashes in production. I believe this is the kind of situation people are trying to avoid with type safety...

> Maybe the more serious problem is that people want to be able to quickly say "I want a Fibonacci-Tree<K,V> for types K and V"?

That's uncalled for, isn't it? There's a lot of non-toy problems solved elegantly and pragmatically using generics. I personally enjoy how Entity Framework uses it.


> Except when it isn't.

Yes, but by far more important are bounds checks. Go has bounds checks. As a C programmer I don't get to enjoy them (I get to write simpler, non-GCed, object-cruft-free software in exchange). Out of bounds reads and writes consume far far more of my time compared to void pointers. (And even OOB are not that time consuming).

> That's uncalled for, isn't it? There's a lot of non-toy problems...

Yes, the Fibonacci was a bad example (couldn't use Map because Go has that). It wasn't meant in a mean way.


> Yes, but by far more important are bounds checks.

Sure, but I'm failing to see why having other checks isn't important. I mean, generics aren't hard to use... They're way easier to grasp than Channels (a great feature), and easier to use daily than go generate. I dunno.


Many things are important, and most things require making tradeoffs. When a thing that is only a little bit important prevents something else that is more important (albeit more subtle and requiring experience to see), it's probably better not to choose the first thing.

Generics are abstract. They lead to bad error messages. They make the language more complex. They require syntactical support as well as special magic under the hood. Look for various resources by Russ Cox and Rob Pike (and maybe other Go designers). For example https://go.googlesource.com/proposal/+/master/design/go2draf...


I'm familiar with that article, and it got me excited for a while, but it's about compiler implementation, and it doesn't really have much to do with the current discussion, other than rationalizing the opposition for the feature.

About your other points: nope, generics wouldn't remove simplicity in the language itself. They would mostly legitimize with type-safety certain idioms that are already present in current Golang code. And the terrible error messages of C++ templates are not really a good example. There are much better languages now when it comes to generics.

I suggest that maybe you try looking into other legitimate uses of generics? The Fibonacci-Tree<K,V> example you gave earlier is unrealistic, and the other example being thrown around here, STL, is too complex... There are lots of legitimate reasons for someone wanting generics in a language, and nobody is advocating for them out of bad faith, or wishing to kill a nice language with feature bloat :(


First go does have generics. It just doesn’t have user defined generics.

But to answer your question go has really mediocre support for a wide variety of problems. Some that burn me a lot is support for future/promises and support for modern lock free algorithms.

So you end up either writing non-optimal replacements, losing type safety or in some case code generation is used.


>Some that burn me a lot is support for future/promises

This doesn't make sense in Go. Nothing is asynchronous in Go, everything is blocking. You use goroutines to execute multiple tasks at the same time. That's a big part of what makes Go simple: it's a lot easier to understand sequential code than spaghetti callbacks and promises (it's somewhat similar to async/await in the JavaScript world).


Yet open up nearly any large golang codebase and you’ll find a channel being used to return a single answer response in the future.


What's wrong with that? Go has channels thus it doesn't need futures/promises.


Some problems are more simply modeled as futures/promises than csp.

Go’s unsophisticated type system makes it difficult to write a good standard generic data structure library such as a future/promise library.

That leads to people either writing a poor replacement, not using that style, or losing type safety. This is precisely what you would predict upon learning golang doesn’t have user defined genetics & ive had it bite me more than once in real projects.


Yeah, and that's why Go code is a spaghetti of communicating via channels, rather than callbacks.


Go channels are very handy and magnitude of less spaghetti than futures. And goroutines have good performance.

I think people are used to futures etc, that's why the new concept feels strange.

I think the goroutines and channels are the biggest features which compensates for generics.


Each code in each goroutine is synchronous. That's what makes it simpler than callbacks.


Callbacks are prolific in Go; not sure where you're getting this from...


use channel + goroutinue for that.

Goroutinue are very light weight. Zero size channel works like promise


Which makes code even more messy than just using Futures.


You'd have to use an equivalent of `void *` (for Go, it's the empty interface: `interface{}`). However in 99% of the cases the builtin slice and map data structures are enough.


You generally try to design your list so it contains types with common methods by using an interface (not the any type interface{}, mind). You could have a list (slice or map) of io.Writer, where it can contain any type that implements Write([]byte) on itself.


They make use of code generation like early MS-DOS C++ compilers, check Kubernetes source code.


Time for Go++?


If I had the time, I'd love to apply the C to C++ diff on top of Go (templates, overloading, etc.), release it as Go++, and watch the world burn. Just for the lulz.


Not at all, generics like CLU (1975) does, would already be better than the current state.

http://www.pmg.lcs.mit.edu/CLU.html


My understanding is that the standard library containers implement generics via special compuler magic, and everyone else is using `interface {}`, which is the equivalent of a void point or "any" type in Go.


It's really not the equivalent of a void pointer, because interface{} is still typed, and you can still interrogate its type, and the runtime prevents you from using it as any type other what it actually is. So it's far safer than a void pointer, although it can crash the program — but cleanly (because of the aforementioned runtime checks).


It's not strictly speaking "standard library containers", but rather "builtin containers".


As many others have stated, there are options. In the linked list example, you could use:

- container/list.List which uses its own Element with internal pointers and interface{} for values

- write a type-specific implementation (not generic, but no runtime type assertion)

- write your own implementation using your own node / element interface type (maybe your list is generic to types that support io.Writer - generic for some use, but if you need access to specific types, you're back to runtime type assertions)

- write your own interface{} implementation (constantly needs runtime type assertions)

- use code generation (maintenance is harder, potentially non-standard tooling / build steps, but hey - no runtime type assertions)

- use a slice instead of a list (Go's version of vectors / dynamic arrays) - still requires some implementation, but the language has a lot of built-ins that make this easier. Depends on use. If you are doing a lot of insertions in the middle, this may suck, FIFO may suck and you need to be careful about not doing append()-shift and effectively leaking memory, LIFO this is dynamic and gives you good cache locality. Up shot is no-runtime type stuff and at least the slices themselves and the built-ins are generic.


Interfaces help a little bit. You can't really build re-usable data structures without falling back to `interface{}` and then incurring a performance hit from using reflection to get a well-typed value back out; but you can at least make your bespoke structures very marginally more reusable by defining interfaces ad-hoc.


To be clear, you use cheap type assertions to get a well-typed value back out. You can use expensive operations from the `reflect` library to do other things, but not to get a well-typed value back out.


Looking at some benchmarks it does look like newer versions of Go at least have pretty reasonable performance for type assertions. That makes the situation a little less bad, but doesn't negate the general ugliness of having type assertions every time you want to get a value back out of a generic data structure.


Fully agree; dealing with `interface{}` is generally pretty tedious.


I believe this is done using protocols / interfaces where you declare a shared api of the objects


Go has a kind of generics that also maps cleanly to machine-level generics: interface{}, which is like void* in C.

Whereas all the other kinds of generics, I believe, can't offer this quality. They require a lot of machine code instanciations (like C++'s template system). Or at least, in the case of virtual functions ("dynamic polymorphism" with VTables), they cause more brittle abstraction boundaries. Think how in C++, when definining a class, you need to expose a lot of internal details in the header file -- list all the private member functions and fields, etc. This has lead to the so-called PIMPL idiom which is exactly what you do in Go or C.


If void pointers are "generics" as you say, then the word is pretty much meaningless. Every language I know of supports that kind of construct and you can usually dump it everywhere as much as you like.

Generics specifically refer to the parameterization of types using types. Go doesn't have user defined generics.

The only reason in C++ why you need to define all the "internal details" in the header file is because the compiler needs to know the size of things. You can write completely template free code that requires all your classes to be defined in headers or you can litter your code with templates, put pointers everywhere and place all your classes outside of headers. It has nothing to do with generics and everything to do with how the rest of C++ is designed.


Thanks for the correction, I shouldn't say "generics". But rather "Go programmers don't have user-defined generics, they use interface{}" or something along those lines.

Other than that, I don't think we're in disagreement here.


You don't need to expose any internal details on other languages that make use of generics.

Even on C++ this is be eventually a thing of the past, after modules get finally adopted.

Using how C++ currently does as argument against generics is a pretty weak argument, given the various ways to implemente them since CLU and ML introduced generic programming into the world.


Layouts of separately compiled classes/structs must still be exposed to the compiler. You can't hide layouts away, they are part of the interface. With all the disadvantages that dependencies bring.

> Using how C++ currently does as argument against generics is a pretty weak argument, given the various ways to implemente them since CLU and ML introduced generic programming into the world.

I would be interested to know how you think the problem of tighter coupling (a.k.a dependencies) is solveable, because I don't see a solution. For example, I'm pretty sure that typeclasses in Haskell are implemented with either of those two approaches I've mentioned depending on the situation.

(Maybe it's possible if we require more information for the linker? I haven't thought through this.)


Exposed to the compiler doesn't imply exposed to everyone else to see.

It is solvable by not sitting in an ivory tower using C++ and Java as the typical examples why Go won't get generics, and instead engage with generics friendly communities.


> Exposed to the compiler doesn't imply exposed to everyone else to see.

Personally I care about true, hard dependencies much more than that "exposed for everyone else to see" fluff (the latter being only a subset of the former). Probably that is because I don't do business software, don't work in big teams etc.

What really matters to me is reducing hard technical dependencies, and recompile times and ABI compatibility may only be the two biggest reasons.

You're probably aware that I program predominantly in C, and "sitting in an ivory tower" is not a word that I would apply to typical C programmers. I wouldn't apply it to Java programmers, either. It's normally a term for the academic world, the world from which languages that focus on type theory originate.


I am applying that term to Go developers against generics no matter what.

C does provide minimal support for generics since C11, with improvments planned for later standard revisions, as anyone that works predominantly in C should be aware.

And yes I am aware that I kind of reversed the meaning of the term, but that is how it feels all the Luddite arguments against generics.

Just because there are plenty of old tech languages, which many in the generics crowd have a large experience using, doesn't mean we should keep using such approach at expense of productivity.


> I am applying that term to Go developers against generics no matter what.

They are actively looking for something that doesn't suck. Aren't they?

> C does provide minimal support for generics since C11, with improvments planned for later standard revisions, as anyone that works predominantly in C should be aware.

Not sure what was your intention behind that statement. But of course I'm aware of C11 Generics. And they might be nice for a generic min() and max() and similar but other than that honestly I have little use because types are not values and in C, types are not elevated to be much more than simply physical layout. Whenever I've tried to encode meaning in types in any language I've failed spectacularly. Feel free to make Oddintegers and Evenintegers all day long if that's what makes you happy.

> And yes I am aware that I kind of reversed the meaning of the term, but that is how it feels all the Luddite arguments against generics.

Let's get a life and not spend all of our time raging against people doing different things differently. At Google, I'm sure Go does solve real headaches they have with C++ ((re)compilation issues being only the worst offenders) and Python (performance...). And probably it does so better than any other language can. Because, Google is still primarily an engineering company, not a hipster company, nor a language-obsession company.


> They are actively looking for something that doesn't suck. Aren't they?

It looks more of "we are working on it excuse" to keep people at bay.

Rob Pike has done a presentation last year where he stated that he doesn't have anything to do with it and is very sceptical of it being ever added.

So WIP is kind of euphemism.

> Not sure what was your intention behind that statement.

That even languages born before generics are willing to move forward.

Google is majorly a Java, Python, C++ shop. Go is usually more outside than internal Google projects.

If we reduce Go lack of features to stuff that C doesn't provide, maybe bounds checking, modules and GC aren't required as well.

As for complaining, projects like Docker and K8s ensure that those of us that rather not use Go, have to deal with it in some form anyway.


> If we reduce Go lack of features to stuff that C doesn't provide, maybe bounds checking, modules and GC aren't required as well.

Well that was the initial basic design frame: A systems programming language that removes some of the headaches of writing distributed systems software with the use of a GC and Channels/CSP.

It was intended from the start to have more features and tradeoffs than C has, and it even backed up pretty quickly from trying to be a competitor in the (not-distributed) systems programming space, didn't it?

> That even languages born before generics are willing to move forward.

C11 Generics are a pretty limited feature, basically a central switch on types instead of values. They are not a big deal. And maybe Go decided against them because Go has RTTI. In any case, C11 Generics are decidedly different from what many people expect from a Generics in Go.

> As for complaining, projects like Docker and K8s ensure that those of us that rather not use Go, have to deal with it in some form anyway.

Dude... 1) They are not Go. 2) If you don't like them don't deal with them. 3) Don't make an elephant from a mosquito. 4) Show us some of your beautiful systems software written in perfect OOP style in languages from 1975 already! We need real world proof that there is a supreme super-typesafe OOP way with functional bells that solves all of our problems!


C++ comes to mind.

Also some would say that Go is actually from 1968.

http://cowlark.com/2009-11-15-go/


interface{} is the equivalent of C++17's std::any, of which you can put anything including vector (slice) and maps.

If you really want high performance with many different types of a function, its a case of copy-paste-modifying your code.

Its a language that is straight-forward, its the antitheisis of tmtowtdi.


You use an interface.

Golang use duck typing. It is very flexible and very simple. (Some times too simple)


So how do I make e.g. a TreeSet of something, put my elements in, and get them back out as the same type, without casting?


>Have you ever seen someone write something to the effect of “I would use Go, but I need generics”? Perhaps we can infer from this that many of the people who are pining after generics in Go are not, in fact, Go users.

This is the sort non-adhominem adhominem attack that makes these debates so tedious.

Obviously, someone deciding not to use Go for lack of generics after giving it a serious try would end up not being a Go user. Does that invalidate their opinion?

The logic of this argument is strikingly cult-like. Any criticism coming from non-adherents is automatically disregarded on the basis of it coming from non-adherents.


In addition there are plenty of people who do use Go yet still criticise its lack of generics. But apparently these are not “real” Go users?


This article highlights very well why designing a programming language without generics is a mistake. Adding it after the fact is not trivial, especially if you have high standards wrt simplicity and non-redundancy.


I agree. C# still has the legacy of its pre-generics era. It's not super-bad, but it still hangs around like a bad smell. If it ever gets higher-kinds then the current implementation of monadic types with the hacky extension methods will also hang around like a bad smell.

It seems crazy to me that language designers of modern statically typed languages wouldn't go for the state-of-the-art. I see the comments about simpilicty, but generics makes [working with abstract types] simpler (in my humble opinion, of course).


You're implying that there is a better design that has generics and caters to the same programmer folks. But you don't show what that design is. The OP didn't imply there was one.


D, Rust, C#, ML, Delphi, etc.


I haven't used all the other ones, but "Delphi" really made me crack up. I used it for 6 months before I quit my job. It's a mess, junk after junk added on a pile of junk, only surpassing the junk-adding badness of C++ by also having this broken standard library that's somehow required to write any type of software (because the simplest thing, C-like pointers, exist but are really not nice to work with).

The task that lead to my decision to quit was to write a data serialization systems for datastructure that I didn't know in which version of junk they were expressed, by interfacing with the broken standard library. The serialization system was to replace another serialization system that somehow didn't quite work. No wonder, it was broken code, and I couldn't see a way to write non-broken code to solve an unsolveable problem.

What's nice about Delphi is that the compiler is quick and it has a beginner-friendly IDE with a visual GUI creator (no selling point for me). That's about it, AFAICT.


I was referring to generics systems that don't suck.


I don't think so. The article explains also that generics as implemented in other programming languages bring a lot of complexity and that generics aren't mandatory.


You already have the complexity in Go, just without type safety. You already have boxing in Go, all interfaces are boxed, so you can easily add Java/OCaml style parametricity without even any changes to your runtime.

interface{} is already promoted to heap, they are pointers, all you need is to swap interface with type parameter and add a couple of hundreds lines of code to the type checker. The theory is all in the books and there are dozens of compilers implementing it in practice.


I realize I'm not the audience here, but still -- As someone who isn't terribly familiar with Go, most of what I'm seeing in this article is the shady corners I can't see into.

The generics one, I've seen plenty of pixels spilled on, and I've come to accept that I won't really grok the debate unless I spend some serious time programming in Go. What about the module system, though? Can anyone explain or share an article on what's so great about its module system?


Exactly. If you can't get rid of your favorite paradigm (which seems to be generics for some reason in this thread) then I guess stick with the language you are already using and don't try to wrap your head around other languages?


An algorithm or data structure may be applied to various types of data. There's various ways to handle this. Macro expansion, generics (basically equivalent of macro expansion but as a language syntax), or losing types: void pointers, duck typing, interfaces.

Go puts it's head in the sand and and handles the problem like it's 1970 with the "void pointer" way of thinking. That's fine if you're using a dynamic language (ie python, lisp) and firmly decided your trade offs with regards to types and performance. But if you elect to use a statically typed language, it would be nice to reap the benefits.

Modern C++ is still the only way to go for serious software. Rust maybe in the future as the compilers improve. Go is a no no-go.


I don't speak from experience with Go, but a simple type assertion at an interface boundary should normally not be noticeable at all. Where performance matters, there you usually do not have parameteric types or similar. Have you measured anything?


> Modern C++ is still the only way to go for serious software.

Please define serious software.


I don't understand how not having generics is at all acceptable. But maybe that's because I come from a functional programming perspective.


I programmed in Java and Haskell and have made the switch to Go some time ago for my current position.

I don't miss them - it's just a different way of programming but I've not ran into a problem that I couldn't overcome because they are missing.

OTOH, I've shot myself in the foot quite a few times with Generics.

Honestly, just _try_ it for longer than an exploratory session. Try to build something big with it, and see if you still miss it.


As a rule I don't learn "trendy" things until the fad period dies off (be it a netflix show, a product, an app, a diet, or a language).

But basically lodash is my bread-and-butter. Could such a library even exist in a language without generics?


The question is, why _should_ such a thing exist in a language without generics? It's just a different programming paradigm.

Program into a language, don't program in a language.

The functional approach is just one way to solve the problem. Also, as a side-note, when I program at home I'll often take a functional language. It's just a different way of programming and I do like FP (Haskell mainly). But Go is different, not worse or better.


I will probably never opt-into a language for the rest of my life that is not-hybrid (able to be functional or procedural).

Because hybrid is objectively better than only supporting one.


It's not 'objectively better' to be honest. Offering two ways of doing the same thing can lead to a non-uniform codebase, and can lead to people being 'experts' in functional and others being experts in procedural. And at some point, the procedural guys will get a mindfuck reading the functional people their code.

(We had something similar happen).


It's because Go is a brutalist hipster language - simplicity above utility. Forget a lack of generics, you don't even get proper error messages.


Is "hipster" a label you would like to apply to e.g. Russ Cox? Maybe the designers of Go have design goals that are different than what you have in mind. Maybe they don't see it as "simplicity vs utility", but more as "utility through simplicity".


"Hipster: A person who follows the latest trends and fashions, especially those regarded as being outside the cultural mainstream."

Yep. Go is a hipster language, even if you don't like it.


"The latest trends"? To me Go is particularly conservative.

I don't feel like arguing over a word that has become essentially meaningless over time, but I think you have seriously misunderstood what hipster means or was once supposed to mean. Either that, or you don't really know about Go and are just judging it by its marketing's design aesthetics (Gopher, fonts etc. following a trendy googley style).


Go is trendy and Go is outside of the mainstream in it's minimalist design choices. Are you trying to say that Go is not in fashion and has made mainstream language choices?

I think you're just upset about the choice of the word hipster but as with all words it's a shortcut to actual meaning. It was intended with a hint of playfulness and not intended to make you feel bad, even if you don't agree with the choice of word.


> Are you trying to say that Go is not in fashion and has made mainstream language choices?

I can't even understand how you can be constructing such a statement. "In fashion" and "mainstream" are pretty synonymous to me. In consequence, the statement is contradictory. Hence, No, I am clearly not trying to say that.

> I think you're just upset about the choice of the word hipster

No I'm saying that the team behind Go is just really considerate and principled. They don't follow all the latest fads, simply because those fads are the reason why so many other languages suck and projects written in them become giant unmaintainable hairballs.

They are engineers (label them conservative if you like). Not hipsters.


What a bizarre criticism... If anything Go is a ruthlessly utilitarian language; utility above mathematical elegance. I say this as someone who values mathematical elegance. If I want mathematical elegance, I reach for a functional language; if I want to get something done, I reach (sometimes begrudgingly) for Go (and occassionally Python or JavaScript/TypeScript).


I even think that this utility (to me, it is synonymous with the simplicity from which it comes) has actual mathematical elegance. Whereas functional languages I find not particularly elegant once they hit the real world, must run on real machines etc. It gets ugly, complicated, or slow, really quick.


I agree, but it’s a different kind of elegance that is likely to be foreign to many folks in this thread, and I didn’t want to broach the distinction in this thread.


"you don't even get proper error messages" - what are you talking about? Have you used Go?


Yes. Have you used programming languages with good error messages?


As I understand many Go devs are former python/ruby devs. Its limited static analysis is even great compare their former languages, There are many articles which notice type safety as advantage of Go. So they have easy to learn, very fast language with good support for concurrency/parallelism (Consider what goroutines offer compare to GIL).


You code without them. Ends up making your code clearer in a lot of case, it's pretty good actually. I think a lot of people complaining about generics here are not writing Go


using interface{} and reflect is good enough for the many problems of using X datatype


No it is not. What's the point of a compiler if you check types at runtime? It's just that a lot of things in Go weren't carefully designed and now the price of adding something to the language is the price of dealing with technical debt. For instance Go has a form of exception (panics), returning errors is purely a convention. But panics aren't very good at exceptions either.


Well, what was the point of adding std::any in C++17?

Generics aren't a cure-all, they merely duplicate code and change the type. Its not much better than copy-paste and replace the type names.


> Generics aren't a cure-all, they merely duplicate code and change the type. Its not much better than copy-paste and replace the type names.

Nobody ever said that.

> . Its not much better than copy-paste and replace the type names.

Yes it is. You let the compiler do the job, instead of doing it manually.


Ok, well i just said it, so somebody did.

There is no difference whatsoever between the same function duplicated with different types.


> Ok, well i just said it, so somebody did.

Don't be obtuse, nobody ever said "Generics are a cure-all".

> There is no difference whatsoever between the same function duplicated with different types.

Yes there is, it's called polymorphism.


One of Go's tennets is "clear is better than clever", followed by "reflection is never clear". So no, idiomatic Go is not about using reflection, it's what we have to resort to because the language is so limited.


We're talking about simple reflection here, pass in the value, infer the type and cast to that type.

Most people are totally confused by generics, i personally don't have a problem using them or not. At the end of the day, its just template metaprogramming.


> they feel that generics are a good fit for this language

Or that it's ludicrous for any statically typed language to not have generics.

> It’s small and simple, and every detail is carefully thought out > Nearly all of Go’s features are bulletproof > my opinion are among the best implementations of their concepts in our entire industry

Uh huh.

> You could write a book called “C++: the good parts”, but consider that such a book about Go would just be a book about Go

Or it could be one-liner: "easy concurrency".

> simplicity and elegance are now the principles I optimize for

Doesn't everyone who cares? The problem is that elegance and simplicity, like beauty, are in the eye of the beholder.

To me, generics increase elegance and simplicity.

> If you’re fighting Go’s lack of generics trying to do something Your Way, you might want to step back and consider a solution to the problem which embraces the limitations of Go instead

So pretend it's the 70s and use void* (interface{})?


The way he describes Go's existing feature set as unwavering perfection is disappointing. No language is perfect except in heavily constrained context. They all make trade offs. GC is itself a compromise and so it follows that Go is not the one true language.


Been using Go for 4 years. I totally agree. It sucks to have to use your brain to think about alternative ideas on how to do something. However, I’ve come across much much better solutions to my problems than I would have if Go offered a crutch to my flawed thinking.


> I’ve come across much much better solutions to my problems than I would have if Go offered a crutch to my flawed thinking.

Any example where you have a better solution than using generics?


The problem is the solution is often to make the compiler ignore types all together and use interface {} wholesale, then test interfaces with type assertions.

If Go had a least unions, it would be a bit less painful to describe a range of finite types while keeping things strictly typed in functions and methods. Unions are a limited form of type polymorphism in a garbage collected language.


I'd be disappointed if Go went for unions instead of full-on Rust-like enums, but I agree with your general point.


I keep thinking they could add macros instead but I guess the C++ version is too much history for them to be associated with. It would basically be like code generation at compile time, except much cleaner than the current, version-specific mess of tools.


Macros are another can of worms. Even if they're AST-aware like in Rust, you can do very complicated stuff with them and they are very hard to read/write/debug. This would kill the advantage that it's very hard to write obscure Go code.


>> his would kill the advantage that it's very hard to write obscure Go code.

But it's very easy to spread that Go code into tens of Kloc.

The amount of error handling and if constructs make me feel as if I am readying assembly: predictable AF, but it doesn't help because the volume of the code is huge.


That's so true. It would be great to be able to have very limited / very short macros as a compromise.

    var a = n1;
    if a < n2 {
        a = n2
    }
vs.

    var a = max(n1, n2)
without having to write and make a function call.

I still want something more powerful for error handling like a type that if it is ever assigned non-nil the method returns immediately.

   var err autoreturn error

   rslt, err = pkg.MaybeError()


This is true. But it is go design philosophy not to hide too much magics, it favours verbose, explicit codes.

Design choice. You can't have both.


They have macros. Sort of. Search "go generate".


This isn't a macro language. It relies on an external program that the developer needs to write himself at first place. "go generate" just facilitates the execution of a third party program. It does nothing more, and doesn't even do it automatically when compiling a program.


It looks gross. Why not quote and unquote - it makes it so much easier to reason about...




Applications are open for YC Summer 2019

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

Search: