Go doesn't have generics. To someone coming from a language like Rust, saying that your type system doesn't have generics is like saying your car doesn't have wheels. It's just considered non-negotiable.
Go doesn't have generics. To someone coming from a language like Rust, saying that your type system doesn't have generics is like saying your car doesn't have wheels. It's just considered non-negotiable.
To overburden an analogy, it'd be more like complaining that your tank doesn't have wheels[0], or your hovercraft. Go takes a different approach to the same problem (in this analogy, getting from point A to point B).
But really, this is a rather tired flamewar that gets beaten to death literally every time a post about Go makes the front page, and there's really nothing more that can be said about it. Either program in idiomatic Go, which means using the language as it's designed (ie, without generics, at least in its current form), or don't, but it's very tiresome to see this argument rehashed again and again.
[0] https://en.wikipedia.org/wiki/Continuous_track#mediaviewer/F...
Well, sure, I guess you can pound a screw into things with a hammer but you're missing the point.
1) Methods with names that indicate the parameter types. 2) Method calls on objects to convert some internal struct data from one type to another. 3) Something I haven't thought of that doesn't involve losing a handle on your type.
So there is certainly a loss in convenience, but if you use the type system it can be just as safe as a functional language as far as I can tell. So, yeah, it isn't as intellectually elegant, but it also isn't really that hard to deal with.
The only way to write this kind of generic code in Go is to cast everything to `interface{}`, which can't be checked statically.
If you are still not convinced, one of the things you can do with generics is say "these two parameters have the same type". In Go the best you can do is say "these two parameters are subclasses of something", which is less precise.
You want to use different screws? You're on your own.
Sorry. In the spirit of Go, you're not allowed to re-use this analogy; you're going to need to write another different one that can perform a similar function.
It's ok if you copy and paste some of the text from the first analogy and structure it similarly, though.
Which would be just as bad as for a car, since the things that drive and guide a tank tread are wheels (drive wheels and road wheels.)
Go doesn't take any approach to writing generic code at all.
And then the code I've seen is littered with "interface {}".
That's a pretty big thing to give up, and I don't get the point. Something like F# gives you high level features (and green threads if you want) with fair perf, and Rust gives you a fair amount of language with C perf.
Rust's type system has most of the bells and whistles of C++, plus some new ones. It's clever, well thought out, sound, and bulky. Rust has very powerful compile-time programming; there's a regular expression compiler that runs at compile time. I'm concerned that Rust is starting out at the cruft level it took C++ 20 years to achieve. I shudder to think of what things will be like once the Boost crowd discovers Rust.
The lack of exception handing in Rust forces program design into a form where many functions return "Result" or "Some", which are generic enumeration/variant record types. These must be instantiated with the actual return type. As a result, a rather high percentage of functions in Rust seem to involve generics. There are some rather tortured functional programming forms used to handle errors, such as ".and_then(lambda)". Doing N things in succession, each of which can generate an error, is either verbose (match statement) or obscure ("and_then()"). You get to pick. Or you can just use ".unwrap()", which extracts the value from a Some form and makes a failure fatal. It's tempting to over-use that.
The lack of exception handling in Go yields too many "goto" statements. There's also a tendency to turn the panic/recover mechanism into an exception system. This has roughly the problems of C's" longjmp".
As a practical matter, Go now has most of the libraries you need for server-side programs. (Not GUI programs, though.) Rust has only very basic libraries, and they're not stable yet. The language hasn't quite settled down. People are writing and porting libraries at a good pace, and this problem will be solved.
That is the core reason why there are no generics in Go. Not because the Go team thinks they're a terrible idea, but because they think cruft is a terrible idea.
The default answer to a new feature is "no". When everything seems to be going fine without generics (except for internet flamewars), the answer stays "no".
I find the community's insistence that Go does not have them because they somehow make programming worse to be fairly ludicrous, when there are much more practical reasons. Obviously you can write useful code without generics (C does not have them), but that does not make them useless, or "cruft", or an undesired feature (unless you simply choose to believe that every single person complaining about them does not use Go): you can also write useful code without many other features that Go does have.
There was at one time a fad for extending C with macros like that. Fortunately for program readability, it didn't last.
While `try!()` is a macro and not a core language feature, most of the macros in the standard library can be treated as such. So a Rust programmer will know that `try!()` can return, just like a Java programmer knows that `throw` returns early.
Besides, macros are syntactically distinguishable in Rust. When you see that exclamation mark, you have to rememeber that it's a macro and might be doing arbitrary compile time things along with arbitrary token tree expansion.
For example, bufio.NewReader would probably, in a language with generics, be phrased as a type with respect to a type parameter. Something like (in bastard Haskell)
class Reader a where
Read :: a -> [Char]
newReader :: (Reader a) => a -> BufioReader a
In Go, it's: package bufio
func NewReader(r io.Reader) *Reader
The interface argument is implicitly a type parameter here.This subset of generics covers a wide range of software components, even if it doesn't include the usual container types.
With Go, polymorphism is done with interfaces. Composition is done with embedded fields (and the very convenient method promotion).
That's ridiculous. Plenty of people can appreciate the trade offs between "no generics" and "generics." There's nothing "non-negotiable" about it.
However, I still think the out of the box performance is great and for problems that don't require generics it is a very good option. I especially like the static compiling feature that makes deployments more straightforward. Handling HTTP requests and performing routing, dispatching requests to other services reliable async way is the biggest use case for me using Go. It can totally be written in any other language(Rust), if using generics is a must.
function addKey(input, key, value) { input[key] = value; return input; }
this will work on either Objects or on an Array. But if you have static typing and no generics to make it work you have to either:- create two versions of the same function, one for Objects, 2nd for Arrays
- use any as a type of input - this will work, but you will loose most of the benefits of type checking, e.g. you will be also able to pass Number as an input and compiler won't complain, it will be detected as error only on runtime and other things (your function will also return any so further on in the program you won't know what type is used).
With generic it's easy, you write the function once and when you call it you tell what types are used:
// definition:
function addKey<X,Y,Z>(input:X, key:Y, value:Z):X { ... }
// call:
var a = addKey<Array<string>,Number,string>([],0,"fubar");
With this particular example there are probably other ways as well (sum types, common interface) and also compiler may actually detect passing Number as an error (depends how smart it is), but there are more complex cases, where lack of generics will lead to a lot of copy/pasting and boilerplate.Array<double> means the only element you will encounter is a double.
Array<ISomeInterface> means the only element you will encounter is of type ISomeInterface.
hence, you can express part of some code's requirements via the types that a function,class exposes and/or requires.
these requirements can then be checked at compile time.
without this you have to defer the "checking" to runtime.
Analogies are almost always useless diversions, but this one is particularly ridiculous.
People are building real, working, successful solutions in Go with rather surprisingly regularity (which, if the comparison needs to be made, they don't seem to be doing with Rust). It is obviously working pretty well, and that "non-negotiable" point turned out to not be a showstopper.
A car without wheels? If we have to abuse analogies, more like a car with a manual transmission. People can have hysterics about how will they ever eat their burger while they drive, but somehow some people manage.
I have written hundreds of thousands of lines of Rust code for Servo, the Rust compiler, and other projects. Of course it's a less mature language, but people are building plenty of solutions, including production solutions, in Rust.
;)
I'm one of the people who is currently making a working solution in Go. Are generics the equivalent of missing wheels? Probably not, but I am absolutely finding it a present and persistent pain point that I don't have something like that or even just overloaded function/method signatures, and instead have to frequently repeat a lot of rewritten code scattered full of lots and lots of if/else cases.
Life could be worse. But the fact that people are shipping doesn't mean it's a language in which people aren't finding a specific missing features to be a problem.
This is specious logic. People are not being told to use Go grudgingly because it is mandatory. It isn't a required component of some entrenched industry dictum. The only possible reason someone would choose Go is because, somehow, it is advantageous to their process. And we've seen an enormous number of success stories with Go recently -- all people choosing to use it for no external reason, but somehow it benefits their project. This is in contrast to, for instance, JavaScript (which debatably has its own merits) where if you want to script on the web client, that's your choice, love it or leave it. In the Go domain, there are countless alternatives.
I find it hard to even express clearly why Go feels so...natural and productive. But it does. And one of those reasons is that the language is so simple and, well, crude, that you don't stop and sit on questions of approach. Somehow it works.
If we need to stick with vehicle analogies, it's more like someone is using a dumptruck to move massive piles of Earth, but complaining that the steering isn't as light as their car.
And FWIW, when people talk about the lack of generics causing them great pain, usually they aren't making a solution, but instead are toying with the language. Doing the typical "make a library that solves all problems" sort of thing. When I am using Go it is almost always for a specific, practical requirement (as duct tape between processes, to orchestrate some high performance C code, etc), and it just...isn't a problem. It really isn't. Unless you're making library code it just isn't this issue it is held to be.
You're registering this objection on the basis of JS's privileged status in the browser; I'm invoking it because of The Fine Article's comparison with JS on the server, where it's adopted as voluntarily as any other language -- and where, yes, despite claims that event-driven/callback scattered code are worse than what Go offers, people are able to get things out the door anyway!
And that's true of Node, it's true of PHP, it's true of Java, it's true of most languages people have moved to Go from.
The claim that being able to ship in a language doesn't mean it's wart-free is a pretty solid one, and that's what we're talking about.
> I find it hard to even express clearly why Go feels so...natural and productive. But it does
Does it? I've been working in it for 8 months and... nope. Doesn't feel unusually productive. But I guess your subjective opinion that you can't explain should trump everyone else -- after all, we're using "specious logic!"
> And one of those reasons is that the language is so simple and, well, crude, that you don't stop and sit on questions of approach.
Ah, yes. It's like Java:
"I liked programming in Java mainly because I found it very relaxing. With a bad language, like say Fortran or csh, you struggle to do anything at all, and the language fights with you every step of the way forward. With a good language there is a different kind of struggle, to take advantage of the language's strengths, to get the maximum amount of functionality, and to achieve the clearest possible expression.
Java is neither a good nor a bad language. It is a mediocre language, and there is no struggle. In Haskell or even in Perl you are always worrying about whether you are doing something in the cleanest and the best way. In Java, you can forget about doing it in the cleanest or the best way, because that is impossible. Whatever you do, however hard you try, the code will come out mediocre, verbose, redundant, and bloated, and the only thing you can do is relax and keep turning the crank until the necessary amount of code has come out of the spout."
http://blog.plover.com/prog/Java.html
(When I started working with Go last May, I had no idea or expectation of the extent to which I'd have thought this article would apply.)> And FWIW, when people talk about the lack of generics causing them great pain, usually they aren't making a solution, but instead are toying with the language.
Really?
> it just...isn't a problem. It really isn't.
Oh. Sorry, then. I'll just realize that the unpleasantness I've encountered working with it really isn't there, and I'm not focusing on solutions.
You misunderstand my argument. If someone is begrudgingly complaining about JavaScript in the browser, well they have a legitimate gripe because they really have no option (beyond various compiles-to-javascript kludges). If those same people used nodejs, on the other hand, which many people do, they clearly found some compelling reason to do so. In the case of node it was that it made code very easily, and by default, asynchronous, instead of the classic .NET/PHP synchronous model. There was a benefit, and people gained from it.
Really?
Why are you using Go? Are you solving a real problem? Did you say "here is my itch, and I am using Go to scratch it?" I have never seen, in these discussions, people solving actual problems complaining about Go. Instead it's the code tourists who want to do some flippant, vaguely directed project and then add "Go Guru" on their resume to give credibility to their complaints.
Apparently. I have no idea why JavaScript's position in the browser is relevant at all to the point that being able to ship in a language isn't evidence that its featureset is ideal.
I do invite you to argue the point further, though. And please continue to ask questions like this again:
"Why are you using Go? Are you solving a real problem?"
Yes, please do imagine out loud that everyone who's critical of Go is just not building real software in it. Hell, follow your "argument" to its natural consequence: anyone not using your personal flavor of Blub is probably just farting around.
There is absolutely nothing drawing anyone who doesn't want to use Go into using it. There are zero external forces or dependencies that are making you build solutions in Go.
So when you come telling a tall tale of your peril with Go, it just stinks. Do you understand? You can, from the outside looking in, have criticisms of the language, but when you try to add authority to your claims by manufacturing great experience, it sounds absurd.
The relevance of JavaScript -- and this really doesn't seem that difficult, though I think you're trying to be difficult -- is that, to reiterate, people have to bear it regardless of their feelings about it, so there are a lot of people who despise JavaScript but ply their trade in it daily. There is zero parallel with Go, where there is absolutely no reason for anyone to ever make use of it if it doesn't offer some significant advantage to their project.
Or because of the hype (and that they didn't know any better), which is quite common in the industry nowadays, unfortunately.
In a similar fashion, the Go designers were surprised that, what they thought was a C++ replacement, did not attract C++ programmers.
But even so, I agree the wheels analogy is too extreme. I'd maybe say that it's like hearing that a car uses two motors instead of a differential -- "weird, I thought we solved that problem a while ago..."