Hacker News new | past | comments | ask | show | jobs | submit login
Channels Are Not Enough (gist.github.com)
235 points by kachayev on Sept 14, 2014 | hide | past | favorite | 221 comments



Go doesn't let you build abstractions - it offers what it does, and if its not enough - tough luck.

What I dislike worst is the denial of the Go community and creators, claiming that generics are too complex and that you don't really need them.

I dismissed Go not because of its lack of abstraction power, but because its authors and community is incapable of admitting problems when they see them. A similar problem with CoffeeScript (conflation of declaration and assignment + scope rules) and the authors' refusal to admit that there is a problem also made me dismiss it entirely.

Every language/platform has problems. But not every language is in denial of them. We should all avoid those that refuse to acknowledge their problems - because that points to a much deeper, much more serious problem - a problem that cannot be eradicated with technical means.


> I dismissed Go not because of its lack of abstraction power, but because its authors and community is incapable of admitting problems when they see them.

For what it's worth, I have had a similar experience.

One time I expressed a personal opinion on G+ about something I don't like about Go personally. A Go fan re-shared this in the Go community and it turned into a debate. https://plus.google.com/+RalphCorderoy/posts/ZfaM1a21tyW

People argued that my concern was theoretical and would not happen in practice.

Then, by chance, someone wrote a totally unrelated blog article about their actual experiences writing Go. The article was overall positive about Go, but among their list of dislikes from using it in practice was exactly the concern I had voiced.

I posted this to the thread and the response I got was: "When I read that, he didn't give an example of it coming up. Again, it seems purely hypothetical."

Apparently a person writing about their experiences who says "There are a few things about Go that I'm not super happy about, and that tend to bite me from time to time," and then talking about problem X, is not enough evidence that X actually happens.

I took from this experience that, at the very least, there is a strong bias against admitting problems.


I'll just leave these here: https://groups.google.com/forum/#!msg/golang-dev/ZTD1qtpruA8...

https://github.com/clipperhouse/gen

I'm sorry you got the impression of that there is a strong bias against admitting problems. I haven't seen that bias at all myself. Instead I've seen a willingness to look at different approaches to the problem and an unwillingness to compromise the other design goals of the language.


TBH, neither of those solve the same problem generics / parametric polymorphism were created to solve: being able to abstract over types when writing a function or data structure.

The first link deals with automatically generating things like printers or comparison functions. Its orthogonal to type abstraction - for example, in Haskell you would use "deriving" or TemplateHaskell macros to do the same thing. This kind of code generation is useful for creating monomorphic functions that depend on the structure of a type (for example, a comparison function for that type) but it won't help you latter create polymorphic functions that work on any type (for example, a sorting function that receives that comparison function as a parameter).

The second link suffers from a similar problem. The only types that can be used generically are the ones defined together with a "//gen" comment and you also can't define your own generic functions (for example, a SumOfDistinct function that composes Sum and Distinct)

You are giving me the impression that people are trying to solve Go's generics problem with tooling when its actually a language design and type system problem.


> You are giving me the impression that people are trying to solve Go's generics problem with tooling when its actually a language design and type system problem.

Go community lives in 1993, back when C++ compilers shipped with code generation tools (mostly macro based) and templates only existed in CFront.


> I'll just leave these here

Are these links in relation to generics? Generics weren't the issue I had been posting about.

> Instead I've seen a willingness to look at different approaches to the problem and an unwillingness to compromise the other design goals of the language.

For what it's worth, if the people responding to me had said "yes, what you say is a potential downside of our approach, but we think that the advantages of our approach outweigh the disadvantages," that would have been fine. There would have been no need to debate anything further.

The reason the argument went on is because the Go advocates were dismissing the possibility that my concern had any validity whatsoever.


> https://groups.google.com/forum/#!msg/golang-dev/ZTD1qtpruA8...

Everything in there listed as impractical in Go is possible in D without external tool, with just regular meta-programming:

- generating parsers from grammar https://github.com/PhilippeSigaud/Pegged

- embedding files as array of bytes:

    ubyte[] = import("file.jpeg");
- protobuf files at compile-time: https://github.com/msoucy/dproto

- generating tables at compile-time with CTFE

Instead of copying what works the Go leaders pretend it doesn't work.


The fact that it's not necessary to explicitly state which interfaces are implemented by a type is a key design decision in Go. It's not going to change.

Every language decision has pluses and minuses. I think most Go programmers feel that this problem is fairly hypothetical because it doesn't seem to come up for most people in real code. But, you're right, it's possible for it to come up. Every language decision has minuses, including this one.

But the pluses outweigh the minuses, so this is not going to change. Sorry.


But FAQ clearly states that generics are open issue. Something changed?


> What I dislike worst is the denial of the Go community and creators, claiming that generics are too complex and that you don't really need them.

That's not the claim. The claim is that generics add complexity to the language and its ecosystem. That, I'd hope, should be an undisputed claim.

Go's lack of generics is a design tradeoff. The occasional piece of awkward code is worth the overall reduction of complexity at an environmental level.

The Go creators do not deny that generics would make things easier. In particular, concurrency is one area where some kind of parametric type system would be really helpful. But we, and many others, are finding Go to be a great tool for a wide variety of jobs. It has won developer mindshare specifically because of our focus on simplicity. It doesn't seem worth compromising that to reduce the occasional bit of repetitive code.


> The claim is that generics add complexity to the language and its ecosystem. That, I'd hope, should be an undisputed claim.

I strongly dispute/oppose that claim.

1) Generics don't add any complexity to the rest of the language. If you don'y use generics, you're back to the "plain Go". Especially since generics doesn't mean just "ML-style polymorphism"; I'm pretty sure that many people would be happy with a very limited implementation of generics, e.g. only for reference/pointer types (or even only for interfaces), with all types/generic arguments declared, not inferred. In that case, implementing generics would only require a change of the type-checker of the language, or in the case of Go, not even that, which brings me to the second point:

2) Generics are already implemented in Go (the compiler/the language/the libraries), via map/arrays/slices, it's just not accessible to user code. I really can't see how anybody could make an honest claim that "Go is avoiding generics because of added compiler complexity", when that complexity is already there.


The answer to the question "where should complexity go?" is always "as low as possible". Complexity at higher levels interacts with more code and begets more complexity. The lack of generics or macros is complexity that is forced on the end user which could be handled by the compiler (language devs).


Implementation complexity is not the issue.

The issue is that a programmer needs to understand how the generics model works and how it interacts with every other feature of the language. That makes the language more complicated, which (as you say) leaks into the higher levels.

Generics is just one of many features that Go could have, but does not because it makes the language bigger.


Simple languages shift complexity to the programmer's shoulders.


Writing more code is not the same as more complexity. Irritating, perhaps, but not more complexity. A larger language overhead to keep in mind is more complexity.


More code is more complexity from a maintenance point of view. You have to maintain n copies of the same code, specialised to n types. Find a bug in one, hopefully you'll remember to correct it for all n.


So if I have a larger language overhead to keep in mind, that's more complexity, but if I have a larger codebase overhead to keep in mind, that's not more complexity? You're trying to have it both ways, IMO.


That depends on the addition of code obtained by limitation of features in a language. If the additional code base is so severe, that it increases the complexity significantly, I'd argue you have chosen the wrong language for the job.

Of course, a codebase in it and of it self can be complex, regardless of language (and even if the language is well suited for the job), but I am only talking in the context of when features (or lack thereof) in a language increases the codebase complexity.

But a few more lines in the same function to do the same thing as a single line in another language, is not more complexity, that's just more lines. It's not like the lines now are somewhere obscure or in another function.


> That depends on the addition of code obtained by limitation of features in a language. If the additional code base is so severe, that it increases the complexity significantly, I'd argue you have chosen the wrong language for the job.

Agreed.

> Of course, a codebase in it and of it self can be complex, regardless of language (and even if the language is well suited for the job), but I am only talking in the context of when features (or lack thereof) in a language increases the codebase complexity.

Agreed.

> But a few more lines in the same function to do the same thing as a single line in another language, is not more complexity, that's just more lines. It's not like the lines now are somewhere obscure or in another function.

And here's where we begin to disagree.

I delete redundant comments in code, even if they're correct.

This is significantly more effort than leaving them alone: I have to recognize they're redundant, check VCS history to ensure I'm not missing something, create a changelist, request a code review for the changelist, wait for the reviewer to verify I indeed didn't missing something, submit the changelist, verify the changelist still builds (you never know when you'll hit a bizarre compiler bug, corrupted file, conflict resolution related typo), merge the changelist back to the mainline...

This is a significant amount of work! But I feel it's justified: they're increasing the complexity involved with reading the code. The more pointless redundant comments I'm reading, the less important things I can remember, and the more likely I am to skim over something important such as a bug.

This is not additional cyclomatic complexity in the codebase. Structurally, the complexity of the fundamental operations my program performs haven't changed - I haven't touched anything that should affect the final executable output in any meaningful form at all. But I'm still making it simpler* to read.

(* a synonym of simple to note: noncomplex!)

In non-comment code, the problem is much worse. More code means more opportunities for typos, more code which must be read to grok the actual execution of the code. If you thought bugs got missed when I was skimming past the comments, well let me tell you, it's way worse when I start skimming past the code! And this happens to everyone.

There are still a few people who don't mind writing all their programs in straight up assembly. Sure, it's a bit more code, but all the if and while conditionals from C aren't reducing the cyclomatic complexity of their programs either compared to structured programming with conditional jumps. They say there's more important things to worry about than pure line count - and they're entirely correct. They're writing codebases in assembly that I'd find much more readable than some of the codebases I've read in much much higher level languages.

But having addressed the more important stuff I'd still like to address the less important stuff. It eventually adds up, and I've seen it make me more productive. (This has encouraged me to try many different languages... so far not Go, I've yet to come up with a problem which makes it the right language for the job.)


I think that the "complexity" cost of generics is overstated, really. Can you explain how generics make user code more complex?


They refer to the complexity of the compiler and language, not to user code complexity. Any given language has a complexity budget and they wish to expend it elsewhere.

(Note that I am in disagreement - I do think generics should be added).


That's a weird stance. If there are complexities that programmers face that can be absorbed by a compiler, it must be, because that would pay off for every programmer , in every project, in every bug prevented.


> If there are complexities that programmers face that can be absorbed by a compiler, it must be

Not sure. If absorbing it would make the compiler much slower, much more complex, or the compiled code less deterministic, or corner cases in the compiler much more numerous, I think it may be reasonable to not go this path.

It looks like the go compiler in itself is a nice piece of engineering, like a F1 race car. And a bunch of guys say they want it with automatic gears. Proposing an automatic version would change too many things in the internals, and the result would be another kind of cars.


> If absorbing it would make the compiler much slower, much more complex, or the compiled code less deterministic, or corner cases in the compiler much more numerous, I think it may be reasonable to not go this path.

Why would that be the case for Generics?

I think nobody says "Go needs Generics, but the implementation needs to be horrible."


In the Go FAQ [1], when they list the purpose of the project, the first answer they give isn't about concurrency (as some might suspect), it's:

  "It is possible to compile a large Go program in a few seconds on a single computer."
They've been consistent about this. It's a major design goal and, for some, compilation speed is worth more than support for Generics.

[1] http://golang.org/doc/faq#What_is_the_purpose_of_the_project


Any language with modules and generics and production quality native code compiler, does enjoy fast compilation speed.

It is a good sell when the audience only knows about C++ compilation issues.


Last time people were ecstatic about go compilation speed, the speeds cited didn't even hold up well against gcc.. The go compiler is not very fast, but as you point out the features of the Go language makes it amenable to fast compilation.

What kills compilation performance for larger C/C++ projects is include hell and managing build dependencies, which as you point out is mitigated in language with modules.


And with luck, even C++ will finally have modules. Still need to wait a few more years, though.


And yet, the dmd compiler for D support templates and is faster than the gc Go compiler.


I'll say it again: Go doesn't have generics because of implementation complexity. The tradeoff was against the additional complexity that our users would have to deal with.


I don't know where people would have gotten that idea from: https://golang.org/doc/faq#generics


right, because a big codebase to deal with the lack of generics doesnt add complexity at all.

you see, the problem with the complexity of a language isnt real. it is perfectly possible to avoid generics in c++ forever. but there will come a day when you think to yourself, was it really worth it to be this lazy? then you take a peek and (assuming you understand generics by then enough to use it a little) suddenly half of what you have writen so far is for the bin.


I was only addressing the comment of the parent that suggested adding parametric polymorphism would kill compiler performance.


DMD isn't faster than the go compiler anymore


You've said this several times. I believe you, but can you please link to your source? There aren't a lot of comparative compile time statistics out there. Last time I checked, dmd was quite fast regardless--maybe no longer faster than the Go compiler, but within the same ballpark.


No, that is not what I was referring to. It is definitely user code complexity that turns us away from generics.

People tie themselves in knots with generics all the time. Just look at pretty much any mature C++, Java, Scala, etc codebase.


As somebody using pre-generics Java libraries from time to time, I can say with confidence that generics are not the cause of complexity. Casting from Object is a source of bad type safety and doesn't help with documentation. The complexity you'll find in a mature codebase is a function of the way it is architectured and the complexity inherent to the domain, mostly.


I wish people wouldn't assume there's only two options - Generics or casting from Object/interface{}/void* It's a straw man argument. No experienced Go programmers are trying to say that's a good way to write code. The idea is to restructure your code so that basic data structures and interfaces pick up the majority of your reuse scenarios.


I'm no Go programmers, but I relatively often need to take a parametrized basic data structure as storage and write a parametrize class on top of it, while hiding the data structure because it's irrelevant.

Well, I guess I'll keep not being a Go programmer :)


I'd say people tie themselves in inheritance and interface knots more often than generics knots. Especially invariant generics are rather hard to get wrong - they place such constraints on the types that most operations are unavailable.


> People tie themselves in knots with generics all the time. Just look at pretty much any mature C++, Java, Scala, etc codebase.

That's not my experience at all. Generics are generally not a source of pain. Do you have any specific examples of your claim?


People tie themselves in knots with classes/packages/interfaces/concurrency/computer code all the time. Just look at pretty much any mature codebase at all.


I think trade-offs have been made already. If they bring in "generics" they would have to back-pedal and now many in the community would have to in a way refute their previous excuses of why they didn't need generics. ("But I have been arguing on public forums for the last 2 years that generics are not useful, what do you mean we'll now implement generics....")

There is also a chance that it will slow down compilation and or runtime. Java, C++ and other code compiles slower. Is it because those languages are stupid and slow and made by idiots? Not necessarily, it is because they have more features. Many added later (with added complexity of keeping backwards compatibility). The fear I think, is if Go gains those new features, its compilation and/or execution speed or claims of simplicity will not hold any more.


You have it all backwards. We didn't build Go in order to have arguments on a mailing list. And I don't think the people saying "I don't need generics," are lying. I think they actually believe what they say, and I'm sure if we did introduce generics today many of them would say "I think this is a mistake."

Yes, the tradeoffs have been made. The language has been designed. It is very unlikely that Go 1.x will see generics.

Yes, any new language feature may slow down the compilers and/or runtime. Go values compilation and execution speed highly very highly. To include any new language feature we would assess whether it is worth the various costs; that much is obvious.

But there are technical reasons why C++ and Java could never compile as fast as Go, and they have nothing to do with generics. Go's dependency model is the main reason it can build fast.

And simplicity is a core tenet of the language design. To sacrifice that would be to admit defeat entirely. We could have just been using C++ all along.


> And simplicity is a core tenet of the language design. To sacrifice that would be to admit defeat entirely. We could have just been using C++ all along.

Well that was my point it. Turning Go into something like Java or C++ will make it not Go any more.

> We didn't build Go in order to have arguments on a mailing list.

Not sure many popular languages were built for that. But arguments on mailing lists is what you get. Quite often the smarter people are, the better they are able to veil things like disappointments, personal dislikes, and others in technical arguments. I have seen it in private meetings and public discussion forums. The inertia of defending something vigorously and then having to back-pedals is unpleasant.


Simple is the biggest weasel word in programming.

In practice it's pretty much a measure of the temperature of bear porridge that a given person currently finds just right.


C++ currently compiles slowly due to lack of modules.

Eiffel, Ada, D, Modula-3, Active Oberon, FreePascal, Delphi... enjoy fast native code compilers and do have generics.


Lack of generics != lack of abstractions.

The Go community freely acknowledges that generics are a nice feature, and that lacking them is a pain point of Go sometimes. Although many Go developers will tell you that sometimes turns out to be not that often in reality, which has also been my experience.

Rob Pike has outlined the tradeoffs inherent with generics here: http://research.swtch.com/2009/12/generic-dilemma.html

The bottom line is it's not a feature that comes for free, and if most of the time you don't really need it, maybe the costs aren't worth it. That's a bold statement for a programming language these days, since generics is a central feature of every popular, modern, statically typed language. Whether they are right or wrong I won't attempt to say. The language may well get generics one day, but it's early days still and the team is rightly focusing on more important features for the moment.


That really depends on what you mean by "most of the time". After all, you only write a generics based library once, and you reuse it many times - therefore on the outside it appears that you don't really use generics all that much.

In my opinion, depriving a "normal" language user of generics is like depriving a Lisp user of macros. Whatever it is, its definitely not just "bold".


I've done most of my Go programming on library code. A sync library for relational databases to sqlite (for mobile devices) and an embedded database. Lack of generics has bothered me a little, but copy and paste with a multiple-cursor editor really makes short work of it. I think the worst part is really our natural aversion to code duplication and the ugliness of it. e.g. having to write min/max for integers is pretty ugly (although not as ugly as converting your ints to float64 and using the stdlib min/max.) However, I spent more time thinking that it was ugly than writing min and max. Sure it's ugly, but programming is not art, it's engineering, and Go is a language for engineers.


> I think the worst part is really our natural aversion to code duplication and the ugliness of it. e.g. having to write min/max for integers is pretty ugly

Sometimes ugliness is a sign that something is designed incorrectly, especially if the language aids in making that more visually evident.

> (although not as ugly as converting your ints to float64 and using the stdlib min/max.)

Not to mention incorrect.

> it's ugly, but programming is not art, it's engineering

Not mutually exclusive. A good language would make incorrect or inefficient code "ugly" or "uglier" than correct code.

> and Go is a language for engineers.

So are languages with generics like C++, Java, Rust, Haskell, etc.


Plus all those dynamically typed languages which are intrinsically built on the concept of generics (JavaScript, Perl, PHP, Python, Ruby). /sarcasm Nobody uses them because nobody needs generics.


They are intrinsically built atop generics. Duck typing is row polymorphism. Dynamic languages often depend upon that flexibility to operate—and they enable it by allowing everything. Static languages without polymorphism are at a low point in that trade-off space since they restrict useful operations and provide no way to express the invariances needed to recover that flexibility.


I never thought people will actually come up and defend code duplication. It's definitely more than ugliness. The need to fix all the copies when they need to be updated is a bigger problem.


Or the fact that I actually saw someone on the mailing list also implement min() incorrectly due to copy-paste :)

> I never thought people will actually come up and defend code duplication.

Indeed. Some of the responses by some Go fans really leave me surprised to say the least.


It was the community attitude towards generics and code distribution that eventually made me focus on Rust and D.

At least those communities embrace modern computing abstractions and code distribution practices.


It's fine that you don't agree with our tastes, but it would be nice if you could stop coming into every Go thread and being condescending about it.

Like PostgreSQL and OpenBSD, I've been permanently turned off Rust because I never want to be left at the mercy of a community that invests so much time in harassing and insulting others.


We have rules against harassing and insulting others in the Rust community, and pjmlp does not speak for us.


Look, we gotta keep busy while waiting for the rustc build to finish. :(


Please tell me where you've been harrassed and insulted by the Postgres community? Sometimes people come into the IRC channel and say something that doesn't make sense and are told it doesn't make sense, and sometimes those people get very upset, but I wouldn't classify that as harrassment. And that's basically the strongest reaction you'll ever get from anyone in the community.


Any active comments thread related to MySQL attracts a derailing holier-than-thou invasion telling us how dumb we are for not using PostgreSQL. PostgreSQL's advocates haven't quite reached the arrogance level of Oracle DBAs, granted, but they're a lot more active.

I basically stopped using (public) IRC somewhere around 2000. I have little idea what goes on in PostgreSQL's IRC channel(s). I expect it's toxic, but I'd expect that for any project's IRC presence. Public IRC is an inherently toxic medium.


That doesn't sound like anyone I know of who actually works on PostgreSQL, and certainly not anyone I'd consider part of the PostgreSQL "community." The mailing lists, IRC channel and other forms of community communication are much more hostile to Oracle than any other RDBMS, and anyone who tries to start a flamewar there (particularly one about MySQL) is instantly shut down. I'm really sorry that you've been turned off from great technology by the actions of some overzealous Postgres users.


Except, I also talk good about Go in what concerns using it to replace C, specially in possible uses for real systems programming in a GC enabled language.

After all, when compared with the first Oberon version, Go only needs a few more primitives in runtime and unsafe, Kernel and SYSTEM in Oberon respectively.

This is what attracted me to the language in first place.


even if I think it's horribly naive if not flat out erroneous, I can see how someone could feel that way about OpenBSD...but Postgres?!

who is harassing or insulting anyone in the Postgres world?!?!


Yeah, the deficiency isn't the most harmful part - its the attitudes that come with defending that deficiency.


    > I never thought people will actually come up and defend   
    > code duplication.
DRY is a principle, not an axiom.

Overapplication of DRY as axiomatic has led to much pain and suffering.


Agreed! But what this means is that when you decide not to apply DRY, you need to have a reasonable justification. Code duplication in general is a bad thing.


Now you are shifting to a editing dilemma. Code duplication is not machine code duplication which is what really matters at execution time. Reading is also easier (even for non-Go programmers at least familiar with C) without templating-like syntax.


Machine code duplication is spending a few extra megabytes on perfectly valid, if duplicate, machine code.

Source code duplication is a risk of spending an hour, or maybe a day, of developer's time to detect the duplication, change it in concert in several places, with an occasional need of detecting and fixing a subtle discrepancy between the copies.

RAM is $0.015 per megabyte. Developer time is $50 per hour.


You could also spend that developer time trying to untangle code reuse between various components, or the more subtle breakages caused by changes that don't account for the expectations of all callers. Code reuse is still a tradeoff.


It should be noted that generic code is harder to break. It is, by definition, less entangled with its callers. There are also fewer operations you can do with generic parameters, so there are fewer ways to screw up.


Code duplication is definitely a programmer problem, not a machine problem. It's also a major problem. Code duplication increases the probability of programming errors, and makes maintenance harder. Any modern language with poor tools for keeping duplication at bay is suspect.


"My editor makes it really easy to do this terrible thing, so it's okay!"

I'm sorry, I quite enjoy many aspects of Go - but the argument that committing one of the cardinal sins of programming is okay because your editor makes it easy is worse than the actual language shortcoming itself.


Code duplication is not a cardinal sin of programming. In fact, the attitude that it _is_ has probably done more harm to [modern] programming than duplication ever did :)


This comment wins the thread!

Sorry, I meant to say that the language's shortcomings, even if temporary, start to attract a wrong attitude, which is sad (and you, golang team, should feel sad).


OffTopic: This sync library is available?


Correct me if I'm wrong but doesn't the current state of affairs (using Interface{}) have all the downsides of Java's boxing but without any of the type safety?


It reminds me of the wonderful fun days of Java 1.2 - anybody remember how proud Sun was of how everything derived from object so you could use the untyped containers for everything?


The main difference with casting to Object is that you can use type switches or safe casts which return an additional success boolean, to restore type safety quickly after taking the item out of its container. Yes, you can type-test in Java before you type-cast, but it isn't idiomatic, and it isn't syntax.


"It's fine in Go to do the wrong thing, because they added syntax to make it even easier to do the wrong thing."


The answer is not that you should use an empty interface, the answer is not to write generic functions.


Which leads to writing the same code repeatedly--because trying to wedge in reusability via insufficiently expressive structural typing is entertaining but often fruitless--and making the user wonder why they didn't just use something modern (setting aside stuff like Scala, even C++ can do channels, and past that the reasons for Go start vanishing real quick).


I write go 40 hours a week and have been for over a year. There's been only a couple times I wanted generics and those are structures I haven't actually needed to reuse yet. I'm not guessing about not being generics much.

Edit That being said, go is not for all projects. Some projects need a lot of generics. Don't use go for that.


Um, I've written Go. Nontrivial amounts, as it happens. In doing so, I recognized that I was regularly forced to write worse code in the pursuit of doing things idiomatically because I lacked the semantic richness of C++, let alone Scala. And this worse-is-better attitude of the Go community gives me a dim view of its future--and between its junk GC and its completely pedestrian semantic and syntactic propositions I already had a dim view of its present.

If you write reusable, future-facing code, generic types without the erasure of interface upcasting is required. There are no two ways around it.


It sounds like you were forced to write/maintain some Go code and are basing your opinion on that, an opinion heavily colored by the quality of the original code and your annoyance at your employer for making you work in something other than your preferred language(s).

It's even possible the software you were tasked with writing/maintaining was a bad fit for Go. I tried to mention that in my previous response. Such things certainly exist, and most Go enthusiasts will be more than willing to admit it.

However, saying you can't write reusable, future-facing code without generics is preposterous. To refute you, all I have to do is point you at the Go standard library. A huge body of code whose purpose is purely reuse, and not a generic to be found.

Or perhaps we could look at the thousands of reusable go packages found on godoc.org.

You don't like Go. That's a perfectly acceptable stance to take. But I don't think you've really given it a fair shake, either.


> If you write reusable, future-facing code, generic types without the erasure of interface upcasting is required.

You're entitled to your opinions, but this is a patently false statement. There is plenty of C code currently running on my machine that was written decades ago and is still actively maintained.

> And this worse-is-better attitude of the Go community gives me a dim view of its future

The Go community actively embraces Worse-Is-Better. If your opinions are well formed enough that you know you want nothing to do with it, then what is your point exactly? Yeah, you hate Go because you hate Worst-Is-Better. So what?


> You're entitled to your opinions, but this is a patently false statement. There is plenty of C code currently running on my machine that was written decades ago and is still actively maintained.

You're right. Sorry. You can do it by enacting a fair approximation of stapling your eyelids to your hairline. I apologize for not being exhaustive.

> The Go community actively embraces Worse-Is-Better. If your opinions are well formed enough that you know you want nothing to do with it, then what is your point exactly?

That I've had more than one long night dealing with an inherited Go application and it sucks and its developers should feel bad.

(OK, the last is mostly facetious. If they can't be bothered to use modern tooling, though, they should be tasked with maintaining their own crap...)


I think the real point is that Go just isn't a language meant for developers:

It's a language meant for sys admins (which explains why it is popular with users of other languages usually used for sys admin jobs).

If your job is glueing a few existing services together, you won't miss Generics much.


Um wow no.

Go is a language for people who write servers. It is really really good for those uses. Look at Docker, etcd, Kubernetes, Juju, Cloudflare, Soundcloud ...

And probably a ton that are internal to a company and not really exposed as a user-facing "Go Application™" (like the stuff behind google's downloads service, some of youtube's metadata processes, etc etc).

I think the fact that early on in Go's life someone called it a "systems language" really confused a lot of people. It's not a systems language. It's just a language. The channels, goroutines, and standard library happen to be really useful when writing networked servers.


Well it obviously depends on what kind of code you write. People writing certain types of libraries may benefit far more from generics than you would.


> Rob Pike has outlined the tradeoffs inherent with generics here: http://research.swtch.com/2009/12/generic-dilemma.html

First of all that post was written by Russ Cox.

Second, it already has been discussed multiple times that it only focus on C++, C#, Java approaches while cleverly forgetting generics implementations exist in multiple forms since CLU (1974) introduced them.

But Go advocates take that page as dogma and toss it around every time a generics discussion comes up.


It doesn't even cover C#, just C++ and Java. C# has it's flaws certainly, but it's a baffling omission.


In the comments, where the flaws about the document are pointed out.


The problem is that the code that needs generics is reusable abstractions in libraries. Thats probably 1-3% of code but it is also critically important and there is no convincing workaround.


That is Russ' blog post, not Rob's.


> [...] but because its authors and community is incapable of admitting problems when they see them.

What evidence did you see to make this conclusion? I can only find from their FAQ[0]:

"Generics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do.

Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a design that gives value proportionate to the complexity, although we continue to think about it. Meanwhile, Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly.

This remains an open issue."

[0] http://golang.org/doc/faq#generics


That answer has been there for a while. There hasn't really been any indication that the issue actually is open, other than a refusal to state outright "no generics in Go".

I can't decide if my biggest problem with that answer is that it suggests that the primary use case for generics is generic containers (when, really, the main benefit of generic containers is being able to implement generic algorithms on said containers, like pmap), or whether it's the suggestion that breaking type safety in a statically typed language is a feature.

interface{} is barely an improvement over void*. The need for it suggests an insufficiently powerful type system. Go should either have a type system powerful enough not to need an explicit convention to avoid it, or it should have been dynamically typed.


Quit whining.


I believe that this is evidence enough that they're downplaying the importance of generics.

Specifically, the claim that "maps and slices" can replace the ability to write abstractions such as futures, promises, observables as well as generic function such as map, reduce etc comes off as either naive or disingenuous

Furthermore, the "cost" of these features seems overstated to me. A lot of languages and runtimes already implement generics without significant compile-time or run-time overhead - why is it that hard for Go to do that?


I don't have the hard numbers to back up the cost question, but I believe one contributing factor to the claims appearing "naive/disingenuous" to you may stem from the fact that you may be looking at the language Go from a totally different perspective than the creators when they first envisioned the language (I could be very wrong in this regard):

"Go was designed to address the problems faced in software development at Google, which led to a language that is not a breakthrough research language but is nonetheless an excellent tool for engineering large software projects"[0]

They go on to list some concrete points on the type of problems they are trying to solve:

   - slow builds
   - uncontrolled dependencies
   - each programmer using a different subset of the language
   - poor program understanding (code hard to read, poorly documented, and so on)
   - duplication of effort
   - cost of updates
   - version skew
   - difficulty of writing automatic tools
   - cross-language builds
So while I can see generics helping their goal of, say "duplication of effort", I can also see it negatively impacting bullets "different subsets of the language" and maybe "poor programming understanding" since debugging generics can be extra-painful.

I might not agree with the way they value generics but to me, it does seem reasonable given their design vision and goals.

[0] https://talks.golang.org/2012/splash.article


With the right implementation debugging generics wont be hard. It doesn't have to be C++'s version of generics.

And I'm not buying the poor programmer understanding argument. Generics aren't that complex, they're just parameterized types. The fact that basic language libraries such as maps and slices cannot be implemented without them speak volumes about how fundamental they are when building abstractions.

My point is that most of the backpressure against generics seems to stem from perceived added complexity to the compiler and type system, and thats all. But I'm not convinced thats a valid argument. Truth be told, I'm not a language implementer. But I know that fast compilers and runtimes that implement generics exist, so I don't find the whole discussion believable.


> But I know that fast compilers and runtimes that implement generics exist, so I don't find the whole discussion believable.

Are you arguing that an implementation of generics in a programming language is free? (Whether it be performance or implementation complexity.) Because if not, then you admit there are trade offs. If there are trade offs, then it is conceivable that some circumstances (including programmer tastes) may lead to a valuation that is different from yours.

"Performance" of the compiler is a critical goal of the Go project. Could you point out for me an industrial strength compiler that supports a type system of your liking that can match the compilation speed of the Go compiler? (I can't think of one.) Because if not, then I'll have to invoke this: talk is cheap, show me the code.


> Are you arguing that an implementation of generics in a programming language is free? (Whether it be performance or implementation complexity.)

I am.

Performance: if you replace all generics with interface{}, you get performance that is at better or equal to current Go code.

Implementation complexity: You could add some constraints to generics, for example only interface types can be used as generic parameters, and all uses of variables/methods/functions with generic types need to have generic parameters given. In that case, there's no complexity for code that doesn't use generics. Also, generics could actually be implemented as a preprocessor that would simply insert appropriate casts from/to interface{} at calls to generic methods. Since all variables/functions in Go are declared and have known types, you could of course go further and eliminate most generic parameter annotations.


> Performance: if you replace all generics with interface{}, you get performance that is at better or equal to current Go code.

That is incorrect. Using `interface{}` incurs a significant performance penalty at runtime because you end up boxing everything. For example, you cannot cast a `[]interface{}` to an arbitrary `[]A`.

In other words, no, `interface{}` is not `void*`, sorry. If it was, Go would not be memory safe. (See golang.org for their definition of memory safety. It is strictly superior to a language like C, but e.g., less than a language like Rust.)


What I meant is, "better or equal to current Go code using the current version of polymorphism (which is `interface {}`)".

AFAIK it's not possible to write generic Go code without `interface {}` (or, alternatively, duplicating the code for each type).


Yes, but the tradeoff Go takes right now is "slow programmers," or "no generics." You are trading that in for "slow programs." This directly implies that generics have some sort of cost structure and are not free.

`interface{}` is very rarely used for writing "generic" code precisely because of its lack of type safety and performance implications. If you came up with a way to make it type safe without addressing performance, you've just implemented a generics scheme that will cause programs to be slower than they would be without generics (because people would start using them!).


I think it should be clear to every programmer that there are different trade-offs to be made when designing systems, including the trade-off between generic-code&fast-development&slow-speed and specific-code&slow-development&fast-speed. People that don't get that shouldn't be programmers, and people that get it should have the freedom to make their own trade-offs.

In other words, the only "cost" of generics, thus, is the social cost (there is no purely technical cost). Here, it boils down to the philosophical/political freedom-vs-safety question, and I strongly incline towards freedom. Go does not. Go's position is, if not wrong, at least loosing, since programmers demonstrably are using work-arounds (`interface {}`) when they need generics.


> Go's position is, if not wrong, at least loosing, since programmers demonstrably are using work-arounds (`interface {}`) when they need generics.

I just got through telling you that this type of use is actively discouraged, so no, people aren't using it as often as you might think.

If you want generics, you've got to pay for it. The implementation you've suggested requires a runtime performance penalty to use generics. Therefore, you have not demonstrated that generics are free.


D's dmd supports templates and is faster than gc.


Is there any evidence for this claim? After a quick Google session, the best I could find was a forum thread 4 years ago claiming that `dmd` was faster than `gc`. Is that still true today?


Not anymore. You're two years out of date


I think a lot of the complexity even in your examples of passing functions for generic actions like map/reduce is dealing with closures and scope. I don't know enough about golang to comment on its' internals, but as I recall there was a lot of work and effort that had to go into the .Net runtime and compilers in order to support lambdas and generics properly. Which, imho was more than well worth it.

There are likely other issues that golang needs to solve that are much higher priority issues, and there are flexible, even scripted languages that can handle higher level logic problems and scale very well. I wouldn't really expect to have to use generics for most of the problems I would look to go as a first language for a given problem.

Of course all of the above said, I'm a node.js fan and really like what it has to offer. It just depends on your use cases. Go is a really clean language/platform with a lot in the box, that I do appreciate. I would be surprised if they didn't support generics for v2, if not before. But I can see why they would want to punt the issue while there are bigger problems and needs to address.


You're claiming that they think generics have no value. That is incorrect. They just think there are other things that have more value.[1] In other words, they prefer a different set of trade offs than you do. I don't see how this could be reasonably considered "denial."

[1] - http://research.swtch.com/generic


Because they focus on Java and C++ on their arguments while forgetting other languages.


That link has been debunked over and over and over.

Why keep posting it? As you have seen in this thread, many people avoid Go not because it's not a very good language, but because of the way Go people deal with language problems and can't admit issues.

Being dishonest will just alienate even more people.


> That link has been debunked over and over and over.

The only point that post is making is that generics have a cost. Are you saying that is false?

> Being dishonest will just alienate even more people.

What are you hoping to achieve by insulting a large group of people? If your goal is to alienate them, then surely that is an effective tactic.


> The only point that post is making is that generics have a cost. Are you saying that is false?

Did you actually read the article?

> The generic dilemma is this: do you want slow programmers, slow compilers and bloated binaries, or slow execution times?

Wrong.

Additionally, not having Generics has a cost, too. People might disagree which cost is higher (Generics vs. no Generics), but acting as if there was a lower cost solution of "no Generics now, but retroactively add them later" hiding somewhere is just incredibly disingenuous and delusional.

Given your cost argument, there is absolutely no position under which "we don't have plan, but might consider it in the future" would give a favorable outcome. Why not just be honest and tell your users that Generics will never arrive?

> What are you hoping to achieve by insulting a large group of people? If your goal is to alienate them, then surely that is an effective tactic.

Oooooh. Burntsushi pulling his "whine whine you weren't nice to me first!", how unexpected ... not. It's a fascinating pattern which happens as soon as you run out of on-topic arguments.


> Additionally, not having Generics has a cost, too.

The article says it: "do you want slow programmers, slow compilers and bloated binaries, or slow execution times." The first "slow programmers" cost is addressing the absence of generics in the language. Thus, it admits a cost.

> but acting as if there was a lower cost solution of "no Generics now, but retroactively add them later" hiding somewhere is just incredibly disingenuous and delusional.

... Nobody is acting that way. I've said nothing about the relative weight of any cost, nor have I claimed that a lack of generics has no cost. I mean, the link I gave you admits that a lack of generics has a cost right there. You even quoted the relevant portion.

> Given your cost argument, there is absolutely no position under which "we don't have plan, but might consider it in the future" would give a favorable outcome. Why not just be honest and tell your users that Generics will never arrive?

I don't understand what point you're trying to make. Are you saying that the Go language maintainers are purposefully lying to everyone? Do you have evidence of this claim?

> It's a fascinating pattern which happens as soon as you run out of on-topic arguments.

And insulting people doesn't fit that pattern? Yikes.


> Given your cost argument, there is absolutely no position under which "we don't have plan, but might consider it in the future" would give a favorable outcome.

Sure there are, including the following possibilities: 1) There are situations in which generics are a net benefit and situations in which generics are a net cost, and currently Go's target are is the latter, but because of drift in what people what in given domains, it evolves toward the former, 2) New advances in understanding of language design and implementation change the tradeoffs of generics such that they are a net benefit in places where currently they are a net cost, 3) The reason generics are a net cost in the current situation of Go isn't fundamental as a featre, but a matter of opportunity cost given other things that were and are being implemented in Go that implementing generics would tradeoff. A future implementation that doesn't disrupt non-generic-using code once other higher-priority features are implemented wouldn't be a net cost. But that's farther out than Go's current roadmap.

> Why not just be honest and tell your users that Generics will never arrive?

Because its not honest to state a decision that hasn't actually been made.


> New advances in understanding of language design and implementation [...]

"New advances" as in "the last 50 years of progress in language design which we have conveniently ignored"?

There are languages from the 60ies which are better than Go (but lacked Go's distinguishing feature, the Google brand).

> Because its not honest to state a decision that hasn't actually been made.

Given the constraints they have already made a decision.


> "New advances" as in "the last 50 years of progress in language design which we have conveniently ignored"?

No, new advances as in, "new advances". The universe changes, and the context in which the decision not to prioritize generics now was made is not fixed.

> There are languages from the 60ies which are better than Go

"Better" is both subjective and use dependent, and, in any case, that claim is irrelevant to the point under discussion, which is whether or not it is logically possible for the cost tradeoffs to disfavor generics in Go now but favor them in the future.

> Given the constraints they have already made a decision.

Given the current constraints they have already made a decision not to develop generics now.

They have not made the decision you claim that they would be "honest" to announce, to wit, that Go will never have generics.

It may be that it won't, but that's a not a decision that they have made (nor is it a decision that it would likely ever make sense to make. Why ever say "never"?)


From what I've seen is that th Go team has no desire to change the core language syntax at this time. They are spending most of their time on toolchain and runtime improvements.

Go does have generics for map but you can't create your own. I think they will add user generics at some point, but it may be a long while before that happens.


My understanding is that the Go team says they can't figure out how to make generics work nicely, that's why they haven't added them.

Also, type casts don't cause runtime panics. You can use type-based switch/case or check the "ok" return value from the cast to see if it worked.


That's basically what Java said in 1995.

There is a reason why Java completely abandoned that position.


Did Java make generics work nicely, or did they just bolt them on?


> A similar problem with CoffeeScript (conflation of declaration and assignment + scope rules)

That's an issue you simply cannot fix in CS, you need a new language/fork (not having var/let is at the heart of the language's syntax). I wouldn't compare it with Go's lack of generics.


> I wouldn't compare it with Go's lack of generics.

Why? It feels like forking Go would be the fastest way to get Generics.

But on the other hand, the people who are able to pull that off usually just stay away from Go in the first place.


This is in an interesting contrast with Apple's Swift. It seems that Chris Lattner and the Swift team are very willing to listen the input from users in this early phase of the language. The whole way the Swift is being developed is unlike anything else Apple does. Swift core team responds to you in Twitter. The product is released in such an early state that it is frustratingly buggy and slow to use. But it has a regular release schedule and it gets improved in both stability and speed every other week. I don't know if this was agreed on the top level, or did Chris just has enough decision power to just go with this more modern style of release cycle.


I also find Go pragmatic but lacking abstraction power. The other day I needed a stack, and the best solution I could find was this: https://groups.google.com/d/msg/golang-nuts/iwlzqNa4h3g/xCy3...

    to be honest, if i need a stack, i usually implement it for the type 
    in question, or inline, as it's only a very small number of lines: 

    type stack []T 
    func (s *stack) push(t T) { 
        *s = append(*s, t) 
    } 
    func (s *stack) pop() T { 
        n := len(*s) 
        t := (*s)[n-1] 
        *s = (*s)[:n-1] 
        return t 
    }
And that's what I'm using...


It's 10 lines of very obvious code. Isn't that a good thing? Do you really need stack.New<T>()?


Yes, I do think so. Then I could keep thinking about the "business problem" instead of googling for half an hour because I can't believe there is no one reuses a stack in Go.

Also, it could be something much more complicated than a stack, like the data structures in the STL... but that point has already been made elsewhere.


    > Go doesn't let you build abstractions - it offers what 
    > it does, and if its not enough - tough luck.
This seems contradictory. Go offers primitives, and lets you build exactly the abstractions that make sense in your domain on top of those primitives. The argument here appears to be that the primitives are too low-level, which is a fair-enough point, but not at all what you're claiming.


No, your parent is right.

Of course: turing tarpit, greenspunning, yadda yadda yadda, but his point remains: Certain abstractions with a low cost/benefit factor are just not expressible in "idiomatic" Go.


"...incapable of admitting problems..."

From the Go FAQ:

Why does Go not have generic types?

Generics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do.

https://golang.org/doc/faq#generics


If you read the link you posted, you would know why people say that Go devs are incapable of admitting issues.


Seriously?

"...we understand some programmers do... ...we continue to think about it... ...This remains an open issue."


You sound confused. Denying the existence of a problem and not wanting a particular proposed solution are not the same thing.


This is a really great read, and goes beyond just channels and concurrency. It seems to me that Go is designed to discourage developing higher-level abstractions. That was my sense using it in the past, and it's only gotten stronger over time.

Remember that one of Go's primary stated goals is "speed of compilation"[1]. Simplicity and ease of learning are paramount, and it's easier to learn a language where any chunk of code basically follows the same rules as any other.

[1]: http://golang.org/doc/faq#Why_doesnt_Go_have_feature_X


"Go is designed to discourage developing higher-level abstractions."

Yes, that does seem to be the distinctive thing about Go. It's almost like someone read Paul Graham's "blub" essay[1] and thought, "what would it mean to take seriously the idea that blub is the best language?"

Everyone knows that building abstractions has a cost - the cost of building the abstractions themselves, the cost of figuring out the particular abstractions employed in a given project, and the cost of comprehending a language flexible enough to support these abstractions. The hope is that the cost of abstraction is an investment: the time you put in will be rewarded in faster development when you put the abstractions to use. But at some point increased abstraction is going to give diminishing returns.

Now, most programs written today don't involve that much more abstraction than would have been possible with programs written in ALGOL; that is, we haven't seen a huge widespread increase in the power of abstraction used by most programmers in about 50 years. People like Alan Kay and Brett Victor[2] decry this stagnation, and maybe they're right to. But maybe the current low level of abstraction is so durable because it's a sweet spot between the benefits you get from abstraction and the costs involved in coming to grips with that abstraction.

Most people, particularly most people who develop programming languages, assume that we're nowhere near the point of diminishing returns for increasing abstraction. Go seems like an experiment to test the possibility that the maximum efficiency occurs at a much lower level of abstraction than we usually think. It will be interesting to see whether (or in what domains) that hypothesis turns out to be true.

[1] http://www.paulgraham.com/avg.html [2] http://worrydream.com/dbx/


I think what you are missing is that people do use abstraction if you offer it. Java or C# generics or even when C++ added templates. C++ templates where abused but it was done so often that is now standard.

If you look at code from the newer fancy languages people do use these fancy features.


There's a way to make channels easy to use and abstract. Just make a typecast function. Details in a comment on the original post.

The idea is that you create a library which communicates using channel interface. Great. Now you need to add `i.(myType)` wherever. So, create a function that accepts an interface, switches on type (switch i.(type)) and returns a value with your concrete type.

It's a 6-liner solution to most of this rant about channels.


In a statically typed language, it shouldn't be necessary to break type safety to implement basic abstractions. The only thing interface{} provides over void* is safe typecasting.


In other statically typed languages you don't break type safety to implement abstractions.

In go, where interfaces are implemented by default and `interface{}` covers everything, you also don't need to. It's just a little bit (~6 lines) of code to add to guarantee it while they figure out a nice way to add generics.


Well that's not to be sneezed at, even though it remains crude.


Speed of compilation doesn't mean you need a simplistic language.

With Java I can hot reload classes to get instant compilation times in 99% of cases. With languages that use a REPL I don't even need to compile at all until almost all my code is written.


Compilation can be parallelized quite well if the code is structured properly. I used Xoreax grid engine (incredibuild) on Windows some time ago with C++ and it was great at speeding up our builds. Shame C# isn't parallelized in the same way.

Perhaps Go implementers could use similar approach?


As far as I know, correct me if I am wrong, D does have many of the features Go lacks, like generics, and also has very fast compile times.


It's funny that OP uses Twitter as the case study at the end. I wrote what was then the first (and think still the only) Go Twitter client library that works with v1.1 of Twitter's API[0]. It implements automatic rate-limiting/throttling behind the scenes, and it returns values of concrete types (not interfaces) ready for immediate use.

Keep in mind that, were I to write this again today from scratch, there are a number of things I would do differently (since I started it as a relative beginner expanded on it as my familiarity with Go developed, it's grown to be a bit over-engineered in places). But I still think it's a worthwhile example in this discussion.

For concurrency, I wouldn't say that what OP is trying to do is going to be easy in any language, because OAuth in general kind of sucks[1] the Twitter API itself has a number of quirks that make it cumbersome in general, irrespective of language[2]. That said, Go was by far the easiest to work with here, because channels allowed me to abstract the pagination and the rate-limiting in a way that it would be invisible to all callers, but "magically" handled behind the scenes.

Without going into too much detail, I can see that the way OP has designed his code looks a bit cumbersome. That said, while it's a reasonable way of approaching it, I don't think it's actually the best approach in Go given the language's idioms.

One other thing I want to draw attention to is the use of the general-purpose function for issuing a GET request to Twitter, and how that is shared among the various functions that use it to return values of varying, but known, types.

I don't want to use the word "generic" here because people expect a certain thing when they hear that word, but I will say that this function is (A) general-purpose, and (B) type-safe - it involves no type assertions, and the functions all return concrete types instead if interface{}.

[0] https://github.com/ChimeraCoder/anaconda/

[1] Don't get me started on this

[2] I've written client libraries for Twitter in a few different languages, so I actually have a reasonable point of reference on this - at one point, it was my personal "hello world" for testing out a new language.


I'm curious to see this general purpose function of yours. You are also addressing a different point than the article. The main point is that patterns like parallel map are impossible to implement in Go in a type-safe manner. This is a valid complaint depending on what is meant by type-safe and at this point the arguments for/against Go usually devolve into name calling and matters of culture. If you could factor out all that general purpose functionality from your code base, e.g. the rate-limiting and other things, and turn it into a re-usable library then that would be an entirely different matter. Whether that would qualify according to the author's definition of type-safe is another matter.


It looks like this is the function: https://github.com/ChimeraCoder/anaconda/blob/master/twitter...

This looks like a good example of interface{} used correctly - the consumer of the apiGet function passes in their strongly typed object, which then is handed in to json.Decode. No type safety is lost from the perspective of the consumer, while the json.Decode can operate on any struct type.

Sure this addresses a different issue, but for all the complaints about interface{} I think this is a good use-case.


Rather than arguing about generics in Go again, I'd be interested in reading about how experienced Go developers solve the problems posed in this article. (He may be wrong that there's no elegant solution.)

Also, if it can't be solved elegantly, perhaps adding merge() and a few other important functions to the language would be good enough? After all, Go already has the magic append() function for slices and we get quite a lot of use out of it.


I think that experienced Go programmers simply write the code using the types they need.

I think the essay is entirely correct: there are certain patterns that are difficult to write in Go. It's hard to write generic code that merges two channels into one. It's hard to write generic code that acts as a future.

But it's easy to write type-specific code to perform those operations. Most Go programs do not need to merge channels of many different types. So people simply write the code they need when they need it.

This is not to say that there is no use for generics. There is clearly a use for generics, and examples using channels are among the strongest use cases. I'm just trying to answer your question about what Go developers actually do.


In my experience solutions generally fall into two camps:

1) Create a "generic" version of the function using reflection / typecasts 2) Create a specific version of the function for your use-case

I don't have a ton of experience using channels. My code tends to be very imperative and I add the channel layer at the main application level rather than the library level.

So from his example:

> func merge[T](cs ...<-chan T) <-chan T

You can create a function:

   func merge(cs ...interface{}) interface{}
Then call it:

   merged := merge(c1, c2, c3).(<-chan int)
You lose type safety and pay some penalty for performance. Also merge is harder to write than it would be with generics.

But even languages with generics often have similar issues. For example you can't write a generic min/max in C# either.


You can in Haskell

    min :: Ord a => [a] -> Maybe a
    min = foldl' go Nothing where
      go Nothing a  = Just a
      go a0@(Just m) a 
        | a < m     = Just a
        | otherwise = a0
You can in OCaml

    module Min (M : Comparable.S) : sig
        val min : M.t list -> M.t option
      end = struct
        open M
        let go a0 a = match a0 with
            None    -> Some(a)
          | Some(m) -> if a < m then Some(a) else a0
        let min l = List.fold_left go None l
      end
Point being that these problems with generics are reasonably solved. There are perhaps other problems, of course. OCaml should at least be a suggestion that compilation speed isn't really one of them.


Were there any unresolved issues? I really just couldn't tell, it all looked like general learning curve stuff to me(standard stuff you have to think about when using Go) and that he was lambasting how he chose to implement and what he had to go through to do it.


There's no generalized solution to every generic problem. The "cast to interface{}" is the closest to a linear mapping of generics, but if you're reaching for that all the time, you're doing it wrong. So the only sane answer is, "it depends".

The only use case that I have encountered that is essentially impossible in Go is the "generic data structure". Mind you, that's a bit of a big deal, even if it covered over by "generic" arrays and maps (which, further, does cover over a lot of the cases), but it is also the only case where it is actually a problem. Despite the fact Go is not functional, like, at all, I still find myself using my functional training in minimizing the surface area of an "object" as much as possible incredibly useful when programming in Go. I think if I were only an OO programmer trying to come over to Go I'd have a much harder time of it.

Most of the rest of the time you can solve your problem by asking what the code is really trying to do, pull that up into an interface, and carry on. A substantial portion of the rest of the use case can be covered by providing wrapper objects that compose in another object, probably using an interface as the composition point.

I think in practice, about 80% of the problems that people trying to jam generics into Go are encountering are because they are trying to program C++, Java, or C# in Go. Despite their substantial superficial similarities, Go is not any of them, and idiomatic answers differ substantially. Let me rhetorically underline that... Go really looks like a Java or C# clone if you just read down the bullet points, but there are enough important differences that it's a substantially different experience to program in it. Trying to program Go as C# is only slightly less frustrating than trying to port FP idioms into Go (which is a complete waste of time). The remaining 20% are real problems that Go hasn't got a good answer for beyond duplicating code.

Now. All that said, despite the fact that people not used to idiomatic Go are significantly overstating the problem that is the lack of generics, it is a problem and were I in charge, I'd be trying to work something out on this front. (I actually have a proposal I've probably put about 4 or 5 hours of thought into. In defense of the Go developers, this is a nontrivial problem when you stop just waving the word "generic" around and start trying to seriously create an implementable suggestion, accounting for all the use cases, grammar interactions, semantics, etc.) My best argument is that for a language as mature as Go, this is embarrassing: http://golang.org/pkg/container/ Those are the "generic" containers in the standard library that ship with the language.... all three of them as of this writing, plus array and map. At this point that ought to be significantly richer.

(So, that ought to just about piss everybody off...)

Oh, I ought to add for context that I'm actually pretty fluent in Haskell, and my primary work programming language up to this point have been dynamic languages (Perl, Python, etc). So it's not like I'm not comfortable with generics or incapable of understanding how to use them or anything. If anything, I dare say my openness to other answers and then finding ways to express them in Go may be part of why this doesn't bother me too much. There are other options, most of the time, and they are not generally "compromises", either... they are often perfectly sensible options, or even better options than are available in other languages on a bang/buck basis, such as the trade for making composition very easy and inheritance something fairly difficult.


Talking about how to implement generics generically isn't really responding to my question. The original post had questions about how to implement specific concurrent constructs like pipelines, futures, and so on. So the question is how do you handle concurrency in Go? Are we missing important features that should be part of the language or standard libraries?

Some of these may be one-off generic functions like append() that could be added to the language without adding full-blown generics.


I know this is going to sound like an evasion, but the answer is that idiomatic Go doesn't involve pulling in patterns from other languages, but using ones native to the language.

Futures I can be specific about, though. You simply don't use "futures" in Go. Futures (as the term is used by most languages) are a hack around missing concurrency constructs, and in Go, they aren't missing. Use channels instead. This covers rather a lot of patterns from Javascript and the weaker languages, actually... you don't port them, you simply don't use them. They aren't that appealing once you learn the native idioms, which are, generally, quite a bit better.

Putting a "future" library up on /r/golang is a pretty common occurrence... but they're so trivial they're worthless. It's harder to "use" a future than it is to just do thing the future library is doing.

For pipelines, you just "do" them... you don't set up some declarative pipeline, you just... program them. Sort of like how in the Python world they prefer the for loops to map statements? Same thing, really... if you want a pipeline, just hook things together manually. They may miss out on some abstraction, but, honestly, in most imperative languages I'm underwhelmed by the concept of really generic pipelines. Haskell's making some progress on that front and I've actually got an "in the wild" five-stager, but in the imperative world I'm not sure I've ever encountered in the wild some sort of 6-stage pipeline that was better written other ways.

If any major concurrency pattern is missing from Go, it's an explicitly asynchronous concurrency pattern. However, this can be fixed by library code: https://github.com/thejerf/reign


Interessting. I have not done any go. Could you review go in spirit of you beeing a FP guy? Why does go make it so hard?

Im mainly a clojure guy and we generally belive the CPS and FP go together very well. The new interduction of transducers makes this even clearer and it seams to me this is a feature that go should really think about.


In a nutshell, map, reduce, filter, and function composition are all generic functions, in exactly the sense of generic that Go doesn't have. Lacking all those things, trying to do FP in it is a waste of time. Lacking this foundation, most higher-level FP stuff is also a waste of time, unless there is some other path to it. Even if Go some day picks up generics and gets map, reduce, and filter, my guess is that function composition will never be something you can do in Go.

Note that it does have closures, and makes heavy use of them. It just managed to pick up closures without picking up the rest of FP.

I think this generally fits into the spirit of Go being a really good language for working in a larger development environment, where you can't expect everyone to be expert FP programmers. And, honestly, an intermediate FP programmer is sorta dangerous to your source code, in much the same way an intermediate OO guy is. Go does a surprisingly good job of preventing the intermediate guy from messing up your code too much.

To expand on what I said about the principles of FP being helpful to me in Go even so, here's an example: http://www.jerf.org/iri/post/2923 In theory, there's nothing that prevents another OO language from doing that, but without the structural polymorphism that Go has with its interfaces it's so much less convenient that nobody does it, and, more importantly, nobody thinks that way.

In fact, in some sense I'd say Go is inspired by CSP, but to the extent that CSP involves the creation of these complicated networks of data flowing around, it doesn't really do that. On the other hand, I'm not convinced that's a very practical way to program... complicated networks just become one more source of "magic" in a program. Using CPS-esque tools to make it easy to connect components together is itself pretty powerful.


"I want all this <-done synchronizations and select sacramentals to be entire hidden"

Then perhaps Go is not the language for you. There are a lot of design decisions in Go that seem arbitrarily restrictive at first but are there, AFAICT, to (as much as is reasonable) force programmers to write code where what is happening is explicit and obvious without having to dive down into layers and layers of abstraction to find "the magic".

This is, IMO, a feature and not a bug, but YMMV.


Go has plenty of "magic": garbage collection, maps, slices, channels, goroutines. It just wants you to stick to the abstractions provided by the language and not create your own.

This is fine, it's a design goal of the language, but it's unsurprisingly frustrating for people used to more expressive languages.


> but it's unsurprisingly frustrating for people used to more expressive languages

Speak for yourself. I know you certainly don't speak for me. I love Go. I love Haskell. I love Rust.

There are things in all languages that frustrate me. I can appreciate the particular trade offs made in each language. Believe it or not, I think the language specifications for both Haskell and Go are things of beauty. It's amazing how close the core of Haskell is to just a simply typed lambda calculus. It's amazing at how Go can be so well specified in such a short document with near perfect orthogonality in the language.

Many of your comments in this thread read (to me) as if you're speaking from a position of authority on what the right design for a language is. I think your comments would be better received if you expressed your thoughts as opinions rather than as things you consider facts.


I don't know what in my comment suggests that you can't love both Haskell and Go, but that's certainly not what I meant. Nothing I've said here is anything other than my own observation and opinion.

Thank you for the advice. I'll keep it in mind.


> I don't know what in my comment suggests that you can't love both Haskell and Go

I quoted it in my comment. You said: "but [Go is] unsurprisingly frustrating for people used to more expressive languages." I'm used to more expressive languages too, but I don't find Go frustrating. Therefore, your statement is false.

You probably intended it to read like: "I am unsurprisingly frustrated with Go because I prefer more expressive languages."

Many of your other comments are similarly phrased. The read as if you are privy to some truth that people who like Go do not understand.


I wasn't making a statement about myself at all. The tradeoffs involved in Go's design are well-known, well-explained, and intentional. There is a great deal to admire and respect about Go and its community. Hell, my first comment in this thread was noting that Go's design makes it particularly easy to learn.

If it helps, substitute "it can be frustrating" for "it's frustrating".


> If it helps, substitute "it can be frustrating" for "it's frustrating".

Yes, OK, that is an entirely different claim altogether. Agreed.


I am unsurprisingly frustrated with Go because I prefer more expressive languages, fwiw.

(...and no, I don't think it's particularly wrong to assert that this is the case for other people too; there's plenty of evidence to support that people find the lack of generics in a fully featured language like go frustrating; and it's not surprising what so ever that this is the case)


> I am unsurprisingly frustrated with Go because I prefer more expressive languages, fwiw.

So? My point was not to claim the opposite of the OP, it was to point out that the generalization is false.

> (...and no, I don't think it's particularly wrong to assert that this is the case for other people too; there's plenty of evidence to support that people find the lack of generics in a fully featured language like go frustrating; and it's not surprising what so ever that this is the case)

I guess, if your evidence consists of people on HN and reddit complaining about Go.


or perhaps you know, people I know personally?

A majority of all people who use go? Certainly not.

...but consider that if you see lots of people complaining about something, its possibly not because they're all idiots, or pretentious self important HN posers (who certainly do exist).

The key issue being raised in this thread is that the golang community is dismissive of complaints, even when there are lots of them. and there are, quantitatively, lots of complaints.

That doesn't mean go is a bad language; it means its a popular language in the spot light, and its maintainers and community should probably make a bit of effort to be slightly more humble about that, rather than themselves becoming a pretentious 'there no problem here' self agreeing community.

I think thats a very valid concern, worth thinking about.

(and to be clear; I like go, but I dont visit golang-nuts anymore, because of the community there)


> ...but consider that if you see lots of people complaining about something, its possibly not because they're all idiots, or pretentious self important HN posers (who certainly do exist).

My only point was that just because you like languages like Haskell, that doesn't mean you can't have a fun time with Go. The reason why I said it was to push back against this notion that generics are clearly necessary in all modern languages. We should embrace alternative designs and consider them for the trade offs they make, not denigrate them as objectively incorrect.

If I had it my way, a good discussion of language design withholds judgment and outlines the trade offs. Once the trade offs are made clear, we can start to express opinions (or needs or judgments) based on which ones we want to make. This avoids the popular notion that there is some sort of minimal feature set that makes a language minimally viable.

FYI, these are not well formed thoughts. You could probably poke holes in them, but at the end of day: we should endeavor to balance trade offs in lieu of speaking from authority. (I'm not saying you are doing that, but certainly, others in this thread are.)

> The key issue being raised in this thread is that the golang community is dismissive of complaints, even when there are lots of them. and there are, quantitatively, lots of complaints.

What do you mean by "dismissive"? Most of the popular criticisms have been hashed out repeatedly on golang-nuts. Usually it comes down to the fact that a particular feature doesn't have a known implementation that fits into the design goals of the project.

The design goals are important because they say up front, "Here are the things we think are important and our project will be based on those things. If you think there are other things that are more important, then this project may not be for you."

That isn't dismissive IMO. It is an explicit statement of project scope.

> rather than themselves becoming a pretentious 'there no problem here' self agreeing community.

The problem is that they acknowledge the value of generics but don't know how to incorporate it without sacrificing other goals that are paramount to the project.

Just as you think Gophers blissfully cover the ears in wild ignorance, so to do they think that plenty of others aren't acknowledging trade offs. There is truth on both sides here. It is quite agreeable to say, "I have a really hard time programming without generics, so Go just isn't for me." It is quite another to say, "Go doesn't even have generics? Wow, they just ignored 3 decades worth of PL research."

> (and to be clear; I like go, but I dont visit golang-nuts anymore, because of the community there)

Yes, the community can be very thorny. But I can't blame them. They've been ruthlessly attacked since the start (generics, nulls, exceptions) for preferring a Worse Is Better approach to solving problems.


I find your response condescending and hostile, actually. The parent was making a basic generalization; he didn't categorically claim that his statement applied to all people.

People de facto speak in the form of opinions, and if we are all to qualify our statements with "...in my opinion" for fear of accidentally making an authorative statement, then HN would become a very unhappy place.


> I find your response condescending and hostile, actually.

I don't follow. The rest of your comment posits an argument for why you think I was wrong. If you're going to accuse me of being condescending and hostile, then I think you at least owe me the courtesy of explaining why.

> People de facto speak in the form of opinions

I agree.

> and if we are all to qualify our statements with "...in my opinion" for fear of accidentally making an authorative statement, then HN would become a very unhappy place.

I did not say we should do that.

> The parent was making a basic generalization; he didn't categorically claim that his statement applied to all people.

In a discussion of design trade offs, it is important to distinguish between technical fact and opinion. In language design in particular, it is too easy to conflate these things. This thread, for example, is full of it. (For and against Go, FWIW.)


You don't consider condescension and hostility to be "wrong"?

To be explicit, then, I think your comment's tone was inappropriate for HN. You're taking a generalization and expressing displeasure in the fact that the generalization seems to have inadvertedly included you, and then blaming the commenter for having done so.

You have to be deliberately obtuse to assume that the parent's statement was intended as absolute fact. It doesn't matter if we're discussing technology, this is a conversation, not a textbook; it's a normal part of discourse to give the other party a little slack and not treat every utterance literally and in absolute terms.


> You don't consider condescension and hostility to be "wrong"?

Huh? I used "wrong" in the sense, "your argument is incorrect," not, "you shouldn't do that," precisely because your comment explained how you disagreed with me (not why you thought I was being a jerk). In that way, "wrong" and condescension/hostility are orthogonal concepts.

> You have to be deliberately obtuse to assume that the parent's statement was intended as absolute fact. It doesn't matter if we're discussing technology, this is a conversation, not a textbook; it's a normal part of discourse to give the other party a little slack and not treat every utterance literally and in absolute terms.

I stand by what I said. I don't know what textbooks have to do this. I'm not asking for rigorous debate here. I'm asking for a modicum of clarity in a type of conversation where clarity is important.

I agree that we should give each other a little slack. But I also think we should encourage clarity where we think it is necessary. I think it is necessary in this context.

> You have to be deliberately obtuse

But thanks for the insult all the same. Do you think that is appropriate for HN?


I was commenting about tone, not whether your argument was incorrect. As you say, orthogonal concepts.

The "deliberately obtuse" bit was not directed at you specifically, but then if the shoe fits, etc.


> The "deliberately obtuse" bit was not directed at you specifically, but then if the shoe fits, etc.

Right. wink wink nudge nudge I didn't call you dim technically, but really, I did. Talk about hostility...


> I find your response condescending and hostile, actually.

Welcome to the Go community.


A snarky comment, but I experienced the same on the golang-nuts mailing list. If you dare to question conventional wisdom be prepared to be shot down rather unceremoniously.

At least by now, they updated their docs a little bit.

I still think the "How to Write Go Code" article, which most beginners will encounter, is absolutely misleading by its advocacy of 'go get' - I cannot envision a universe where 'go get' makes sense. You absolutely have to vendor your dependencies if you want any kind of stability with your project.


> You absolutely have to vendor your dependencies if you want any kind of stability with your project.

I have several open source Go projects and I have been maintaining them for years by just using `go get`. I've never once had a stability problem because of it.

Of course, your point is absolutely correct. But I'm pointing out that `go get` can absolutely be useful in some universes. In fact, it's one of the things I love most of the Go toolchain.

So, umm, can we stop presupposing that everyone else's opinion and experience is just wrong?


Agree on that.

My explanation is that there is some kind of positive feedback loop involved:

(1) Go developers/creators think they are really really smart.

(2) Experienced developers see their flaws, stay away from Go, and never participate in the mailing list.

(3) Clueless developers join the mailing list and ask simple/stupid/beginner questions. Go developers can easily answer them, reinforcing their self-assessment in (1).

It's a scary feeling watching their echo chamber ...


My experience interacting with the Go community on golang-nuts was generally pleasant and productive. I haven't experienced or witnessed any hostility, except maybe some hotted debates, but they happen on all programming languages mailing lists. What makes you think the Go community can be hostile?


If there's any magic on that list, it's limited to the garbage collector, and to whatever extent it's magic, that magic would vanish if it were based on strict automatic reference counting.

The others are conveniences to avoid subtle bugs and millions of developers writing the exact same code in every project.

I've mentioned this before, but my experience is that "expressive" is synonymous with "obfuscated". Go helps us in writing clear, maintainable code, not clever code.


Generics also are a convenience to avoid subtle bugs and millions of developers writing the exact same code in every project. That's precisely what they're for.

Any abstraction can be "magic" to people who don't find it appealing or useful. Go includes some of those abstractions and excludes others, like any language. I don't know of any consistent criteria by which the abstractions Go provides are non-magic and the ones it eschews are magic.


My criteria for magic is basically "this is difficult for the average developer to reason about the behavior of". With the exception of garbage collection (with the "asterisk" I mentioned), the things you listed are minimal abstractions which are very easy to reason about.

We all understand how maps, slices, channels, and goroutines work. Their behavior is simple and mostly predictable. Developers working in C wrote these or analogous systems all the time. Over and over again, albeit commonly with subtle errors, particularly with regard to concurrency.

Slices and maps (or their close equivalents) are universal. They exist in a generic form in Go because everybody needs them, in pretty much every significant codebase. There aren't many other data structures for which that is true. Perhaps as importantly, many nontrivial codebases don't really need much in the way of other data structures.

Concurrency features are less universal, but are also the source of many critical bugs. One might reasonably say concurrency is inherently magic under my criteria, but unfortunately some form of it is unavoidable. Go's concurrency primitives at least make it easier to avoid common errors while minimizing additional magic.

My personal problem with adding generics directly to Go is not that they are magic, exactly (which I think you may have misinterpreted georgemcbay's comment to imply), but that they lead easily to magic. Go discourages overengineering, which is a common outcome of certain people applying generics (and there are a lot of those certain people, and I've had the misfortune to deal with their code throughout my career).

What I would like is for something like gen to become the de-facto standard (presumably in conjunction with the generate feature proposed for Go 1.4). I doubt if I'd use it much myself, but that outcome would at least placate demands for generics without making it all that easy to obfuscate what is actually going on in the Go code.


What exactly do you mean by "magic"? Most of the time when I hear people talk about "magic" they usually mean a theory or abstraction that they don't understand or don't want to understand. Are generics magical in your opinion?


What makes things magical or not (the way I think of magical) isn't about the theory of the feature but rather how they are implemented and how much is hidden from the person using them in terms of code complexity and just overall work being done relative to what they think they did.

I'm perfectly comfortable with the "theory of generics", but when generics first came on the scene for C++ back during the time period I used to program primarily in C and C++ they were very magical. Not on the run-time side where the eventual result of any sane compiler is easy to understand, but magical on the compile-time side where when using them it was nearly impossible to determine how much time they would add to the overall compilation and how complex and unreadable the error messages would be if you had a problem. When you make a single simple syntax error and the compiler presents you with an error that is 2 pages long that is the result of an implementation that is, IMO, very "magical".


There is a bit of contradiction in your definition then. I don't think anyone using Go understands how the compiler does all the transformations necessary to get from Go to machine code. In that sense Go as a whole is pretty magical but you seem perfectly happy with that.

Modern application programmers and even system programmers by your definition rely on a lot of "magic". Even the machine code these days is a layer or two removed from the actual metal with all the caching and microcode that reside on the CPU.


Generics appeared in programming languages with CLU back in 1974 followed by many others, C++ was hardly the first language to get them.

The first version of STL was actually done in Ada.

Don't mistake generics in programming languages with what C++ does.


My probken with your "what avg programmer find easy to understand" stick is that this basiclly means, never add anything new.

Many thing common today where 'magic' once. So the line where something is magic is kind of meaningless.


Go doesn't prevent "magic", it just makes you hide the magic in ugly places.

Can't have a flexible iterator system because it might introduce complexity? Better just hide complexity in a next() function.

Can't have generics (except for the google-approved map, slice, chan...) because it might introduce complexity? Better just shift that complexity to unsafe use of interface{}.


It doesn't "prevent" "magic", but it "highly discourages" it.

And again, I think it is a feature and not a bug.

I didn't always think that way, I had a really rough start with Go because I was using it as if I were programming in a slightly different dialect of C++ which it isn't. When I write Go as if it is Go, I just don't see these "missing features" as problems at all.

But this debate has been going back and forth since Go was first made public, so anyone who has tried Go and dismissed it based on these lack of features is unlikely to be persuaded otherwise here and they should continue to use other languages until such a time as Go supports what they want (if ever). That's the beauty of having so many languages to choose from.


I pasted this in the gist comments, and I'll reproduce it here from Hoare's Communicating Sequential Processes: [0]

> But the dangers of convenient facilities are notorious. For example, the repetitive commands with input guards may tempt the programmer to write them without making adequate plans for their termination; and if it turns out that the automatic termination is unsatisfactory, reprogramming for explicit termination will involve severe changes, affecting even the interfaces between the processes.

[0]: http://www.cs.ucf.edu/courses/cop4020/sum2009/CSP-hoare.pdf


Yeah it seem channels are basic primitives. Kind of a like a class in OO programming.

Just like Erlang has explicit processes and message sending primitives So it is pretty simple and concise at that level. In order to build large systems there is OTP (or e2) that embodies and abstracts away some common patterns/behaviours: gen_event, gen_server, gen_fsm, supervisors, logging, distribution between nodes etc.

I imagine over time go will acquire those kind of libraries (maybe it already has them?).

There is also an interesting duality between Erlang and Go. In one case there are explicit processes (identified by PIDs) + an anonymous (implicit) mailbox. Where go has anonymous goroutines but explicitly identifiably channels. It seems they are duals. You can simulate one with another. And you can build concurrency patterns on top of them.

I personally prefer Erlang's model to think about concurrency. There is an active entity -- a client request, a server, a socket handler, it has a an id/name, it can be monitored for liveliness, it can be halted, upgraded, killed, can send messages to it. Somehow to me that makes it easier to map to concurrent problem domains. Channels can ultimately do the same things but it is harder for me to design using goroutines.


The problem (which the article touches on) is that you have to resort to interface{} to make things reusable since Go doesn't have generics. So you have to pick between using a library (which will handle edge cases better) or compile time type checking.


You don't have to resort to an empty interface, in fact, mrust experiences go programmers cringe when they see anyone using empty interfaces. The fact of the matter that much code can reused without being "generic" and often your code never gets reused. YAGNI and all that.


The point of generic code is not purely that it's easier to re-use. The almost more important fact is that generic code has less information about its inputs and outputs—this leads to a smaller design space and, consequently, an easier time designing the implementation and an easier time avoiding bugs.


I think a lot more bugs are introduced from people trying to make their code too generic rather than too specific. The complexity of the code goes way up when you stop being able to rely on certain values being certain types. If I "hardcode" my ID to be an int64, there are a lot of assumptions that become safe to make, like the fact that it's a relatively small value, that I can bit shift it, that the keyspace is of a particular size.... if you then take the same code and decide that the ID should be genericized so it can be anything, now I have to account for the fact that the keyspace could be unbounded (as in the case of a string ID), I can't assume it's safe to copy around the value (it might not be thread safe and/or it might be a really large value).

Saying having less information about the data makes for easier coding is almost always not true.


> decide that the ID should be genericized so it can be anything

You say that, but you probably don't actually do it. If it truly could "be anything" then you would not be able to do anything to it. This is the nature of polymorphism.

So instead, your algorithm constrains the polymorphism based on what you need. If you make use of the properties {small, bit-shiftable, sized, bounded, copy-safe} then you must prove (exactly and only) that whatever the generic variable gets instantiated to satisfies {small, bit-shiftable, sized, bounded, copy-safe}.

Indeed, this is part of how such a system prevents bugs---it forces you to express exactly how much information about the types involved is needed. You can thus reflect better on the kinds of contracts/laws things must uphold and are prevented from accidentally making use of a property of your concrete type which you do not demarcate.

In a truly expressive language you might write

    foo : forall id n . 
          (Bits id, Size id = n, n <= 1024) 
          => id -> {Copy id} id
to indicate all of those properties needed (bounded being subsumed by constraining the size)

Today, you can get promises very similar to the above by using a language like Cryptol[0].

[0] https://galois.com/project/cryptol/


Ideally, the language won't permit you to make such assumptions without making them explicit. In practice, every language falls short of that, and many implementations of generics fall far short of that. Note, though, that manually implemented generics - copy-pasting and changing what you have to - isn't actually any better in this respect.


It would be really useful if Go allowed you to define methods against types imported from other packages. That way, you could define whichever interface you needed against those types (using only its public API, of course) and then use those interfaces for collections, generic functions, and the like.

The closest I've gotten to that has been to create a single-member wrapper struct. Go provides a little bit of sugar for that, but it results in a decent amount of boilerplate and explicit wrapping/unwrapping.


Simply embedding the type and writing whatever additional methods you need is actually incredibly easy. The boilerplate beyond what is required to actually define the new functions is really tiny

    type Foo struct {
        pkg.Bar
    }

    func UseIt(b pkg.Bar) error {
        return otherFunc(Foo{b})
    }
I think that's actually one of the places Go works really well. It sounds like you want something like C#'s extension methods, which I don't think are a good thing (I used them a bunch in a past job). The problem with them is that it means your code can spontaneously and mysteriously break if you move it somewhere else that isn't including the project that has the extensions. Extensions seemed nice, but they really only made the code a tiny bit cleaner, and the added complexity did not really make up for it, in my opinion.


How about replacing certain compile time type checks with smoke tests and runtime assertions, or unit tests?


Why do what the compiler can do for me?


Because you like other features of the language and you just want to get on with it.


Others just switch to a proper language instead.


Inserting the assertions by hand is annoying and error prone - even if you want the assertions to be checked at runtime its still very helpful if the programming language inserts the type checking automatically for you.

Another thing is that assertions can only check primitive type. To check if a function pointer or object respects an interface you need to add an extra wrapper around it to check all its return values (and this is so annoying to do by hand that noone bothers to do it)


The interesting thing about Go, that can help make sense of all its oddities, is that it was not created to assist the developer.

Go was created for businesses, not developers. The holy grail of a corporate programming language is that all individual developer personality is restricted, such that _you cannot tell from reading code who wrote it_. This is all about long-term, large-scale maintainability for massive code bases at massive corporations.

Disclaimer: I work at Google, I do not represent Google, and this is just my opinion after spending time "on the inside".


I understand not having any fancy features in a "corporate programming language", but wouldn't language features aimed at reducing code duplication (like generics) help with maintainability?


I think the extra flexibility gained would be perceived as a negative. The ideal (from their perspective) is that there is only one way to do a particular thing, no matter how verbose it is. Google has recently been mostly Java (Guice, dependency injection everywhere), and has long preferred incredibly verbose code at the cost of occasional duplication.


Agreed, it's likely what you say is the perception. But the thing is:

> The ideal (from their perspective) is that there is only one way to do a particular thing

The lack of useful tools like generics (and others) means there is no single way to do a particular thing: things must be duplicated everywhere (or ugly workarounds to avoid doing so must be employed, like casting from Object or using interface{} or whatever). Surely the benefits of better tools outweigh their inconveniences, even in a corporate environment? This is not a nerdy programmer's whim, but a major software engineering principle of direct consequences for any business.

Taken to an absurd extreme, you can simply copy & paste code everywhere -- that's the simplest programming model there is, and even the most junior of programmers can handle it without having their learning skills taxed in any way. It just leads to maintenance hell, which is why it's frowned upon even in corporate environments.


I think the author could use a technique like this to build the higher level abstractions they want: http://commandcenter.blogspot.nl/2014/01/self-referential-fu...


I remember seeing that post a while ago on Reddit. The impression I got from the discussion is that the whole "self-referential" thing was unnecessary and that the code would be much simpler in a language with generics.

http://www.reddit.com/r/programming/comments/1w2y01/rob_pike...


Wouldn't a library like zeromq address the complications/shortcomings the OP highlights in his article, when working with Go channels on a regular basis? Using the 'inproc' for message transport with zeromq should give similar performance to pure go channels no?

This Go client implementation https://github.com/pebbe/zmq4 by Peter Kleiweg also includes all the examples from the online zeromq guide which is great.

I know it's not a pure ago solution but the OP does mention that

'99% of time I don't really care if the response is delivered with a channel or a magical unicorn brought it on its horn.'

I don't know, maybe I'm missing the point of the article.


Sure, but at that point what is the point of using Go? You might as well use some other language like D if all the parallelism and message passing patterns are going to be handled by a library like zeromq.


Pretty much every article that is posted about Go ends up in a never ending discussion about the absence of generics, which completely drowns the discussions about Go. As a result, the material on the web about Go has a very high noise/signal ratio, which is unfortunate.

Hopefully, the Go team will see this as one more reason to add generics to their language, but until they do that, Go will remain a niche language with a severely crippled potential.


> Pretty much every article that is posted about Go ends up in a never ending discussion about the absence of generics

Well either a lot of developers there looking at Go code are crazy, whiny and in general unpleasant human beings that like to make others' lives difficult or ... maybe it is a problem worth discussing.


I have to credit this as being one of the more original arguments for adding generics to Go: we should do it because it will increase the signal/noise ratio in discussions about Go.

(Personally, I don't mind the ongoing discussions about generics in Go, I just wish they were less repetitive. It's very easy to say "add generics to Go!" It's a little bit harder to actually do it well.)


Yeah I was trying to insufflate new life in this tired debate, glad someone noticed :)


In an essay titled "Why Pascal is Not My Favorite Programming Language" Brian W. Kernighan wrote:

<quote> The size of an array is part of its type

If one declares

     var     arr10 : array [1..10] of integer;
             arr20 : array [1..20] of integer;
then arr10 and arr20 are arrays of 10 and 20 integers respectively. Suppose we want to write a procedure 'sort' to sort an integer array. Because arr10 and arr20 have different types, it is not possible to write a single procedure that will sort them both.

The place where this affects Software Tools particularly, and I think programs in general, is that it makes it difficult indeed to create a library of routines for doing common, general-purpose operations like sorting. </quote>

Kernighan was one of the early C/Unix developers from Bell Labs. It is amusing to note that Go, whose authors come from the same background, getting criticized for something very similar.

[1]: http://www.lysator.liu.se/c/bwk-on-pascal.html


I stopped reading. The further I got the more the article seemed to be complaining not about channels but that Go isn't a functional language. That's right, it isn't.




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

Search: