And I pretty much hate the language. I feel like I'm writing in something that combines the worst weaknesses of Pascal and Java. In fact, Mark Dominus' comments about Java (http://blog.plover.com/prog/Java.html ) approximate my experience Go far better than I would have guessed when I started the project I'm on.
People who seem to be smart nevertheless keep talking it up... some not even as just a good tool but as their favorite language.
So I'll ask: What is it I need to read/work through in order to at least "get" Go and really understand its strengths (whether or not I end up liking it)?
io.Copy(dst io.Writer, src io.Reader)
It reads data from reader and writes to writer... simple. Now what makes this little function so darn useful is it takes anything fulfilling its interfaces (io.Writer and io.Reader). The first way you will probably use it will be to copy between some stream and a file without having to eat up all the memory to store the buffer (not using ioutil.ReadAll for example)... but then you realize you can use a gzip compressor on the writer side, or a network socket, or your own code... and io.Copy works with anything that fulfills its interface.
As you build out a complex application, you start by creating your own functions that take advantage of existing interfaces foo.OCR(dst io.Writer, src img.Image). After that you start building out your own interfaces... like a MultiImage interface that has ImageCount and ReadImage methods that returns the count of images and binary data... but then you realize the images could be big, so you make the ReadImage method return an io.Reader... and now you have gone full circle and are using io.Copy to copy imageX from a stack of images to return to your OCR function that will output the data to an io.Writer which you made actually a gzip writer because text compresses well.
Beyond composition -- obviously, the concurrency and messaging is nice and when you need it vital. The other thing that will help make Go "click" is being very "data oriented" in your design... be vicious and minimal: http://youtu.be/rX0ItVEVjHc (great talk on data oriented design) and be absolutely pragmatic, focus on getting shit done, always...
And how is that any different than any language with interfaces? (Besides the implicit thing?).
I've implemented InputStreams from byzantine transport layers in Java that work with the standard library. I don't quite understand what is special about this concept in Go (maybe it's nice for people coming from typeless, messy dynamic languages or nice languages with horribly inflexible and ad-hoc standard libraries like Python and Ruby).
I read your comment, but this seems more like A sane standard library with proper interfaces and not a language feature per se (also composition to me sounds like the pattern where you create objects which are composed of other objects but that's not what you mean, right)? What you display here can be done in pretty much any language suporting inheritance (or I'm missing something), so your point is those languages don't have io.Copy out of the box?
The strengths of Go to me seem to be its extensive standard libary and the fact that you don't need to worry about writing elegant code because it's not really an option. That reduced decision making is actually really appealing to me on some level, but it's not enough for me to consider it over what I consider better tools (Haskell, Rust).
I'm currently porting a tiny program a friend wrote in Go to Haskell so we can compare notes, and I think the Haskell is both safer and more elegant, but I'm jealous of the fact that all the libraries he used are from the standard library while I have to evaluate libs of varying quality. However, I would rather put my time in to improving the Haskell ecosystem than using something convenient that makes a lot of decisions I disagree with.
edit: I also think there's value in being a conventional imperative language as someone mentioned below. I with there were something between Go and Haskell. Perhaps that'd essentially be Rust with immutable data structures and garbage collection.
Clojure used to have something called, clojure contrib and it was kind of awsome, it did pretty much everything in just one jar. It was also a huge problem to mentain and everybody wanted to be in contrib, so you had the one json lib in contrib and fasters outside.
With clojure 1.3 it got split up into many diffrent parts and it still servs as somewhat of a community standard or recommended library. Overall its much better and much more usful, but sometimes I miss the days when everything was in one jar on on dependency.
As discussed elsewhere on this page, Go is not the most feature-rich language out there.
But it does have features that seem to help my solve my problems with a minimum amount of fuss. Like using interfaces liberally, instead of having to define classes. Having lexical closures is also nice.
If you're not working on an application that can benefit from concurrency, you may not see all the benefits of Go either.
What kind of problems were you trying to solve, and how did Go see heavyweight compared to how you'd solve the problem in some other language?
Most of what I've been working on is a Rest API. Here's an example of a problem that felt like it should be something for which I'd be able to write an abstraction to deal with, but turned out to be challenging, at least as a n00b:
https://groups.google.com/forum/#!topic/golang-nuts/JhsiiGHQ...
(Incidentally, though I moved past my then really poor understanding of Go interfaces, I wasn't able to apply the respondent's answer or my new general knowledge to achieve the abstraction I was looking for, and settled for just grinding out the same code for the dozen entities/endpoints it applied to.)
Concurrency: I suspect there's a bit that's hidden in some libraries we're using, and we may yet need to write our own code for some API requests that get processed offline, but I haven't had to explicitly write code for it yet.
If you can think of a specific exercise that might serve to illustrate Go's outstanding concurrency strengths, I'd be interested to try it and compare efforts to another language or two.
If you have developed software in go, and after a couple months you aren't finding its saving you time, or at least pleasant to work with, maybe its not for you.
I feel like it is similar to C, but more opinionated, with much less rope to hang yourself, and often things I would have used C or Java, I find doing them in golang saves me plethoras of time.
It is opinionated, but for me the aha moment was after I learned enough of the standard libraries to feel comfortable in the language, I find myself getting things done at lightning speed, and it has performance that is as solid as the jvm in your average use case.
I find the code is also pleasant to read, and the language lends itself to writing verbose, simple code, which I find easier to debug than overly abstracted systems.
This, to me, is what he's missing. On the continuum between readable and expressive, Go falls decidedly on the readable side. If you're working on a project by yourself for 6 months, you might not like Go. But if you work on a team or return to code you wrote 6 months ago and haven't touched since, that's when you'll appreciate Go.
Evaluating languages based on simple solo projects will always favor the more expressive languages, but it's a short-sighted evaluation.
What makes Go my go-to language for certain kinds of projects (I'll doubtless be using it again) is that it gets shit done. It has the brutal simplicity and hardware proximity (and raw speed) of C combined with the small handful of things that most significantly contribute to make Java better than C: A simple type system, garbage collection, usable string handling and dynamic data structures (arrays and hash maps). Go also has a fairly large, useful library.
Multiple return values often including errors make error/exception handling very explicit and in-your-face. When something can go wrong, you the programmer are forced to recognize that and deal with it as soon as the function returns. That's a Good Thing IMO. Java-style exception handling, by comparison, looks to me like an elaborate language hack for passing the buck.
There's a ruthless kind of efficiency in Go's surrounding philosophy. There's one way to format Go code, you let the utility take care of it and never worry about formating again. The compiler won't tolerate various kinds of sloppiness, such as unused imports.
As somebody else mentioned, in Go, writing elegant code is not a consideration because it's nearly impossible. Well, I'm sure there are "better" and "worse" ways to write Go code, but not so obviously that I'd be tempted to give it a lot of thought. So I tend to just sit there and write code by the bucketful until I'm done.
Finally, the tooling gets the job done, and quickly. I can compile for and across various hardware environments and ship executables that don't rely on a JVM or other external dependencies.
I'm repeating myself here, but: A Haskell user and a Lisp user are both sure that they're at the top of the power curve, and they're both sure that they're looking down when they're looking at the other language, and they can both tell you precisely why they're sure they're looking down ("It doesn't even have a decent type system" and "It doesn't even have macros", respectively). But they can't both be looking down. What's wrong here?
What's wrong is the assumption that all languages can be ranked by a one-dimensional attribute called "power".
Or look at it another way: Power? Power for what? Well, for writing programs. But what kind of programs? General programs? I've never written a general program in my life; I've only written specific ones. Then "power" is whatever's going to make it easier to write the program I need to write. Whatever language does that is the "most powerful" language for the problem I'm facing.
What power is Go shooting for? It's the power to write a ten-million-line application and have it be maintainable for two or three decades. (That's not my guess; it's what Rob Pike said the language goals are.) If you face that kind of problem, Go may in fact be a very powerful language.
I highly recommend to read this article where Rob lays out the motivation behind many aspects of Go: http://talks.golang.org/2012/splash.article
Then you have the option of using Java, Clojure, Scala, Ruby, Python, Javascript or Groovy languages.
Being good enough, not knowing any better PL-wise, and the Stockhold Syndrome explains that.
This was totally me. I am very much a programming language aficionado (or maybe just a dilettante), and when I first read about Go, I dismissed it quickly. I'd mostly been using Lua at the time, and didn't really understand what was different with goroutines vs. coroutines.
After the initial release, it took us a while to properly communicate the goals and design ethos behind Go. Rob Pike did so eloquently in his 2012 essay Go at Google: Language Design in the Service of Software Engineering and more personally in his blog post Less is exponentially more. Andrew Gerrand's Code that grows with grace (slides) and Go for Gophers (slides) give a more in-depth, technical take on Go's design philosophy.
It was Rob Pike's essay that caused me to investigate it again.
I have been quite impressed with lots of little details that have been 'fixed' (relative to C) in Go. Such as how variables are declared, the module system, and much more. And I was and continue to be impressed with the associated tooling.
I hope that if Go has just one lasting legacy in the history of programming, it will be how it pushed forward people's expectations of what a good language ecosystem should provide.
Some people see languages as a bag of features (immutability! generic programming! laziness! operator overloading! algebraic types! hindley-miller type inference! pattern matching! exceptions! manual memory management!). See http://yager.io/programming/go.html for an example of that line of thinking.
Those people won't get Go.
Designing a language is not about cramming every feature you can think of. It's about making good trade offs.
A trade off is: you get something but you also loose something.
I use Go because it made the biggest number of good trade offs.
Or to put it differently: I program in Go because when writing code, it irritates me less than other languages.
If you want a longer explanation of that: http://commandcenter.blogspot.com/2012/06/less-is-exponentia...
* Lightweight threads with a scheduling and state overhead low enough to run hundreds of thousands of threads at a time.
* Seamless integration with the language, without any rituals or incantations needed to invoke them; you can, for instance, trivially pass closures from goroutine to goroutine.
* A data sharing scheme that makes sense with promiscuous threading ("synchronized" data structures often don't, because they'll end up serializing threads)
Lots of languages have green threads, but not all these properties.
I'm guessing Haskell does? I don't write Haskell, but my impression is that it has everything.
Simplicity - the main feature is all the interesting things they left out.
If you think this isn't important, I will point out that Rust has been frantically trying to look more like Go and less like garbage in every release. Or, I will also point out that the Elixir project exists, which basically does the same thing for Erlang.
It's not suitable for writing an OS, hard real time, highly generic libraries, or GUI programs. Within its niche, it's far better than the alternative, which is usually C++. Just the fact that it eliminates buffer overflows without running slow is enough to justify it.
There are lots of problems with Go. The concurrency isn't safe. The lack of generics forces overuse of reflection and "interface{}", Go's all-purpose type. The lack of exceptions forces far too many lines of "if err != nil { return err}", (or worse, a goto) which takes 3 lines of text every time. The "defer" mechanism is clunky. Lots of modern bells and whistles, from functional programming to generators, were omitted. Other than the lack of safe concurrency, those things don't cause operational problems in your data center. They just require more typing by the programmers. That's an acceptable cost. It beats spending time in a debugger.
If I could go back in time, and discuss one thing with the designers, it would be to fix this.
I'd rather see some kind of Option type (like in Rust) baked deep into the language. Maybe there would be a scheme where you could use these Option types as regular values. The moment you try to use one of them that is actually an error (trying to pass it as an argument to another function without inspecting it first for example), it causes your current function to return an error.
Or something like that. Maybe that's a language design change that isn't going to be worked out in a social media post.
The "defer" mechanism is clunky.
I like defer. Open a file? Defer close it right afterwards in the code. Bam, done! That's nice, and works even if there was a panic deeper in the call stack somewhere.
The idiomatic way to do that in Go, however, can mask errors, like say if Close() returned an error, you might not see it if you just did a 'defer foobar.Close()' Those errors should go somewhere... somehow.
I've seen another way to do it, that works with current Go, in a redis client [1]:
- Function 1 returns rawarg, error where rawarg can be anything
- You want to transform arg into some type, so you create a function that takes a rawarg and an error and returns your type and an error
- In the implementation of your 2nd function, if err != nil, return it directly
This way, as a library user you can just chain your calls without the tedious if err != nil (it will be taken care of in the library).
This might not scale to huge programs, but there certainly is a way to reuse this idea.
[1] https://github.com/garyburd/redigo/blob/master/redis/reply.g...
You can, of course fix that, by wrapping your Close() in an anonymous function that logs an error if Close() had a problem. But I don't see that often in other people's code, and it is cumbersome. There ought to be a better and more concise way to do this.
The golang team has done a fantastic job. It is now my primary language of choice to get things done.
2 years ago I started playing with it moderately, and now in the past 12 months or so it has made its way into my normal workflow and have been delivering completed projects in golang.
I am excited for the next chapter in golang. Keep up the good work!
Most of my work involves building server applications. I have deployed 4 golang apps this year. One is a pre-caching system that concurrently queries a bunch of mysql servers and caches data into redis. Another is a replication system from couchdb to postgresql, and the other two are slim restful api applications that sit in front of elastic search.
The tooling is excellent. A lot of thougt has been put into making things simple. From the folder structure to the final binary, everything is smooth.
It's just a shame that the language design itself is quite behind the times. Older languages had a lot to offer to a new one. The day it launched it was already old. And I don't see a lot of goodwill to change the language to fill the glaring omissions.
Python in this respect is quite an example : iterators, generators, ABC were carefully added without making any less approachable. It prooves it is possible, but that the kind of things the Go leaders apparently simply don't consider.
They have a long way to go on tooling; however, getting to say that is a luxury, due to just how "right" golang has been for systems work. Golang has been amazing to work with, and has just been stupidly productive. I miss debugging (gdb) and generic compile tools like tup, but that's about it!
[0] https://github.com/derekparker/delve
[1] https://groups.google.com/forum/#!topic/golang-nuts/bmsFE3dQ...
A convenient way to do that is ask people to type 'make'.
Platform examples: Host (Cobol, PL/1), Unix (C), Embedded (C), classic Windows (C++, VB), .NET (C#, VB.NET), Java EE (Java), Android (Java), ... Rails (Ruby), PHP (PHP), Browser (JavaScript).
The choice is always between platforms, not between languages. Languages without linking to a platform (Go, Python, Scala, D, Rust, ...) have little chance to succeed.
No, because a language is not (just) a technology, it's a community, and as such, people invest their identities in it. If possible you make an enlightened choice about joining a community that shares your ideas and values and is doing similar kinds of work to you, so they are producing libraries and documentation and hosting relevant and interesting conferences. I often feel that people who lash out at other languages, are people who have come to regret their own choice of community.
In practice is not like I don't have space for 1MB
But I still want proper linking to a shared "golib"
However for Go's current platforms, I would call it a non-issue. Static builds, something seemingly long forgotten though supported in other compiled languages, make deployment and distribution that bit easier.
I would support static builds by default, optional dynamic builds.
And maybe in another 5 years, people will stop bickering over whether that description is/was appropriate. :)