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'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.
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.
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.
> 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).
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.
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.)
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."
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
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 :)
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).
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.
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...)
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.
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.
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.
> [...] 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.
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.
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.
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.)
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.
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?
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."
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.
> 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" 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.
> 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.
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.
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
}
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.
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.
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.