Hacker News new | past | comments | ask | show | jobs | submit login
A year with Go (vagabond.github.io)
237 points by FraaJad on June 5, 2015 | hide | past | favorite | 222 comments



Today, I got a request for a secure message passing service from our CTO. My group, which is a small team of 2 *nix geeks in a company with ~20 mostly c# developers, has become a bit of a skunkworks operation as we have been responding to external constraints and forced to move quickly.

I was able to implement the service per the provided spec in 179 lines of Go in about ~2 hours. Stress tests passed. The job is done. We march on.

Could I have written this service in C++? Absolutely, but it would have taken me 20 hours to get to the same level of confidence. Maybe some could do it on 2 hours; I'm admittedly not a great C++ developer or frequent user.

Could I have written it in Python? Sure, but I would have had to scale and put it behind a load balancer, adding complexity to get equivalent performance.

From what I've seen of Rust, I like it and plan to give it more time now that it is stable. I haven't spent time with D. I played with Erlang. I don't care for Haskell for anything remotely related to "work", but I don't dispute that it has a place in computer science.

In my 2 years with Go, this is not my first positive experience. I have found that Go works well for cranking out high fidelity, snappy services like this. I think this is the result of the language's constraints enforcing simple patterns. Unlike C++ and Python, there are not a huge number of ways to accomplish tasks (at least not ways that feel natural).

Take it or leave it, but I like Go (for certain things).


I don't understand what I am supposed to take away from this though. If you were a strong C, C++, Java, Scala, Clojure etc developer you could equally deliver a highly scalable solution in 2 hours. I haven't seen anything yet to show why Go is fundamentally easier to deliver solutions except for single binary development which isn't really an issue for server side development.


    > If you were a strong C, C++, Java, Scala, Clojure etc 
    > developer you could equally deliver a highly scalable 
    > solution in 2 hours.
I guess the point is, no, you couldn't. An equivalent solution would be less robust/reliable or take (much) longer. Or both.


With some of this languages it would have been much faster AND much more reliable.


    > With some of this languages it would have been much 
    > faster AND much more reliable.
I don't think that statement is validated out by the body of evidence we have about Go. But, this is all hypothetical, anyway.


I think the language doesn't matter It has more Ton so with Ohr Brain. Sole People feeling Continental with go sind bot. Sole Need generis Sole not. Language doesn't matter too much Write The Language which Young Feel is right foR the job


What was your takeaway from the blog post?


> I don't care for Haskell for anything remotely related to "work"

Why not? Haskell seems perfect for this task. It has fast, robust and safe concurrency and GHC's IO manager is highly optimized and insanely fast.


As a * nix geek it's beneath his station. Welcome to the flip side of the academic ivory tower, the scoff at academic stuff because it doesn't "get shit done".


It does "get shit done" for us perfectly, and type-system only helps here. So I still don't see why it's not suitable for *nix geeks. Give it a try!


I read Dewie3's comment as agreeing with you, albeit via sarcasm and cynicism (and some negativity).


Right you are. I'm here all night.


Try building a package with Haskell dependencies for a linux distribution sometime. It is horrifying.


It's not with stackage. You just do pre-setup:

cabal update && cabal install stackage

Building project:

1. clone a project, cd into it

2. stackage sandbox init

3. cabal install --only-dependencies

4. cabal configure && cabal build

If you already used some "lts version", you can put "stackage sandbox init lts-2.4" to second command and it will re-use existing lts-2.4 sandbox without a need to reinstall anything.

That's it. It takes a very long time first time you build with this with some version of lts stackage, and there is some movements towards binary package sets, but I'm not sure on status of that.


IMO this sums up one of the biggest benefits with Go, and unfortunately goes against your own point. There's no need to know about a variety of community built tools, or what's the "best solution" in language X - the std lib gives you what you need. You can stand up a service quickly because it's simple, and there's no "in knowledge" required.


Just built my project on NixOS with no problems. Built it on Ubuntu with a cabal sandbox, no problems. Using stackage LTS I have no problems. Built it using Halcyon as well.

Building with vanilla cabal I might have some issues, but professional haskeller's use the tools mentioned above.


If you have 20 c# devs, why not code it in c#?


cause that's enterprise BS friend, we gotta be more webscale.


Yes, correctly exposed concurrency is a pretty amazing thing. CSP ftw! You could as easily do it in Clojure, Erlang or any language that supports that.


you could also have written it in Java, or C#, and been done quickly with a solid result.

Not sure why you didn't compare to 2 languages at about the same level, and instead went with a lower level and a higher level language.


> Could I have written this service in C++?

Probably. C++ productivity really relies on knowing good libraries, and having the freedom to use them. Without details, I'd wager you could have done it in 300-400 lines. If you gave a brief overview of what you needed, I'd describe my first instinct for doing it in C++.


> I also, apparently, don’t understand Go’s pointers (C pointers I understand fine). I’ve literally had cases where just dropping a * in front of something has made it magically work (but it compiled without one). Why the heck is Go making me care about pointers at all if it is a GC’d language?

Well, sorry, but if that's your level of understanding after one year of Go, I'm furious I wasted time to read your article up to that point.


As I understand it, GO makes it so you can use both a pointer or the object itself to access it methods.

And when you define an object method (or I don't know how it's called when you do this:)

func (*string) uppercase(){

    // make uppercase
}

Then by saying you use a pointer means you will modify the value when you do this: mystring.uppercase()

So it's not really pointers, it's more an idea of pointers.


Things get ugly when your code grows. I had cases where I started with passing pointers to structs around directly, but at some decided that having dedicated interfaces would be better.

But as soon as you're talking interface, pointers don't work as expected anymore, because Go (at least that's how I'm explaining it in my head) passes magic interface values to functions. So you can't just change `func foo(s MyStruct)` to `func foo(s MyInterface)`, but rather you probably want `func foo(s MyInterface)`. Even though you are still explicitely passing a pointer when calling foo() and whatever you're doing with s inside of foo() is working on a pointer -- which your own function declaration doesn't even tell you anymore.

This is one of the things that confuses the hell out of me when using Go.


One of the most unhelpful things about Go's pointer syntax is that it collides with HN's italics syntax. Hence, in your second paragraph, i see declarations which differ only in the slope of the type. Really, does nobody think of this when designing a language?


Are you seriously suggesting language designers should care about every sort of markdown syntax that exists when determining how a language looks syntactically?

Take a step back and think about your statement...


For the avoidance of doubt, my comment was intended as a humorous way to point out to the parent that they had got their code snippets mangled, and i am not seriously advocating Markdown-compatibility as a language feature.

I'm curious, though, as to how you could possibly think i was being serious. Do you spend a lot of time interacting with people with insane ideas?


Yes this was agreed on HN a few weeks ago. Maybe you missed the discussion "proposal for all new syntax to be HN markdown compatible"..?

Try adding /s in your head and read again...


No, it's an unhelpful thing about HN having a terrible partial subset of markdown: ignoring that every other markdown implementation under the sun has more supported markup, all of them provide ways to escape markup characters and inline code sections which ignore markup characters.


I'm on hacker news, so I can't actually tell if you're making a joke or not.


Given an `type IBar interface { Bar() }`, if you implement all your member functions in the form `func (this \*Whatever) Bar() {...}`, then only a pointer-to-Whatever implements IBar, not values of type Whatever. However, since golang can call functions with pointer receivers on values, a member function in the form `func (this Whatever) Bar() {...}` implements IBar on both values and pointers of type Whatever.

See http://play.golang.org/p/ToRh0uK3zw for a demonstration.

Edit: Actually, you can call a function with a value receiver on a pointer value too, so this behavior is inconsistent =/


>Adding proper mutexes to some of our code in production slowed things down so much it was actually better to just run the service under daemontools and let the service crash/restart.

Can the author explain this bit some more? If adding mutexes slows down your code to the point where you would rather just deal with data corruption/races it seems to me that there are issues with your code, not the language.


Yeah, that seems weird. A properly implemented mutex is one atomic instruction in the uncontended path to lock and one more to unlock. And if you remove the mutex, you're turning "the contended path" into "the path that blows up your program". Atomic instructions can be painful on, for example, ARM (where they turn into load linked/store conditional loop + memory barrier) but they shouldn't be too bad on x86 servers.

(I have no idea how Go implements mutexes, though.)


It is not unprecedented, e.g. see:

http://en.wikipedia.org/wiki/Crash-only_software

Martin Rinard at MIT has done a lot of work in this area. It can be safe if you can rollback to a good state to avoid data corruption.

Glitch, my current project, does not bother with reader locks for multi-core execution; instead it can rollback and retry when a write-after-read is detected effects are logged (dependencies are traced so write-after-reads can be detected). It has performance benefits if you can amortize the book keeping overhead, and we need to do it anyways to support live programming (see: http://research.microsoft.com/en-us/people/smcdirm/managedti...).


I'm aware of crash only software (isn't this how Erlang/OTP does things?), however this doesn't seem to be what the OP intended. Running your code without caring about data races means your data can be corrupted and program might not crash.


It actually depends on what the code does, we don't get much context on what the code is actually doing. It is completely possible that data corruption is not a concern because nothing is being written, or there are checksums or whatever...


In this case, it's different. The Erlang/OTP approach involves maintaining internal supervisor trees that are bound to the semantics of the VM and its language constructs, whereas the author's involves using an OS process supervisor (daemontools) to just reexec the program every time it crashes/hangs. The potentials for data corruption and tainted state is higher in the latter, though it's still relatively good for a surprising number of problems.


I think the shitty ARM mutex problem you're describing was fixed in ARM8?


It's amazing how Go caught on.

It's not well designed -- lots of special cases reserved just for the compiler, some bizarro decisions, etc.

It's not modern (with the possitive associates of modern, not fadish, and modern being "the last 30 years of experience" which is still like a millenium in IT years).

It's implementation is not great either. Not a very good compiler, not a very good GC, not good tooling.

My theory is it caught on for 4 reasons:

1) It came from Google, and with some famous names to top. This got it initial publicity in programming sites and media, and Google then coughed for conferences, a spot on I/O etc -- so it caught lots of eyeballs, something independent languages don't have a chance to do.

2) It produces static binaries and this was a real need for lots of use cases.

3) It's easy to get started with, and made converts from scripting languages feel empowered, as if they were "real programmers" writing C, what with "pointers" and static types.

4) It makes writing parallel code for some uses cases easy, which is a good fit for some infrastructure/services apps.

(I don't think most teams outside of Google and some C++ or Scala shops have had any beef with "long compile times" for that to have been a major factor. Though it played to the hype of it being "just like a scripting language").


> It's easy to get started with, and made converts from scripting languages feel empowered, as if they were "real programmers" writing C, what with "pointers" and static types.

What is wrong with this? Exposing people to pointers and static types might give them confidence when writing or reading in "real programmers" code in C

I find the level of sneery nose turning in this thread quite abhorrent to be honest.


There seems to be an idea that some ways of telling your computer what to do are too foppish and that if you are serious about it you use a language from 40 years ago. Of course that's probably what the assembly programmers said about C and there aren't many of those left anymore.


> What is wrong with this? Exposing people to pointers and static types might give them confidence when writing or reading in "real programmers" code in C

I don't see it as sneery nose-turning. Rather I see it as an acknowledgement that the real difficulty of C isn't pointers but rather is manual memory management, which Golang doesn't prepare you for.


I think the author gets closest to the mark in the Conclusion, but still falls short. Go is very attractive as an "upgrade" from Ruby/Python or Java. It's a good replacement for the interpreted languages when speed/performance matters and it makes the async paradigm feel much more accessible. And compared to Java, the fact that Go compiles to a native binary is a huge benefit. It's not a replacement for C or a good "teaching" language, nor would anyone call it "mature" at this point, but it does fill a niche and fills it pretty well.

http://blog.disqus.com/post/51155103801/trying-out-this-go-t...


> And compared to Java, the fact that Go compiles to a native binary is a huge benefit.

I'm baffled by this. I've been deploying Java applications for years, and this has literally never been a problem. You build a WAR (or EAR, or uberjar, or distzip, or whatever). You install a JRE on the machine. You deploy. You're done. It's never been a problem for me, and it's not something that's talked about as a problem in the Java community, which suggests it's not a problem for other people.

When i see someone suggesting that Go has a significant advantage over Java in terms of deployment, i assume that they don't actually have experience of deploying Java apps, they're just regurgitating the standard Go talking points.


> You deploy. You're done.

Then you set your memory parameters. Then you tweak them, to make it more performant. Then you increase them some more to make the GC work less. Then you hook up to the JMX port so you can profile what's going wrong, and identify some XML library as allocating megabytes of strings when it then dumps. Then...

Yeah.


The ability to tune GC and availability of monitoring solutions are things I consider as big pluses for deploying on the JVM.

I would love to have a GC which tunes itself to accommodate the workload. On the JVM, G1 is a step in the right direction. How does Go's GC work in this regard - does it auto-tune itself?

Also, how are Go programs monitored in production? Are there tools like AppDynamics, NewRelic, JConsole or similar APM/telemetry solutions available to monitor Go applications?


Setting memory parameters and tweaking them would be similar to deciding what compilation flags to use when compiling your program. I also much prefer profiling over JMX than re-compiling the application with the profile flag activated and re-deploying.


Yeah. But you don't have to, you're literally complaint that the user has options. It's not like Go doesn't have a GC either.


And the biggest joke is that when you tweak the default settings you often end up making it worse.

The JVM has generally excellent performance with the defaults.


Exactly, and Go's GC is years behind the JVM.


As someone else who has been deploying Java applications for years, I'm not saying it's hard, but you have to take care when upgrading the JRE on a server, because with most setups (such as the default Sun JDK RHEL packages) it's a shared resource. You can go ahead and bundle a JRE with your jars. With Go this specific problem doesn't exist.


Fair point. I've always used the approach of dedicating a machine to one particular application (using virtual machines once those became available), so the impact of upgrading the a global JRE is limited.

I did once work on a system where we installed two JREs in parallel, and selected which one to use for the app based on an entry in the manifest file. That let us upgrade Java versions under application control, without requiring sysadmin intervention. Took a couple of lines of shell script.


I think you must agree that no matter how painless it is, binary < JAR + JRE, in terms of deployment effort.


Depends. For me, creating an uberjar with my default project/package manager is easier than to setup cross-compilation with Go. YMMW.


Why don't they just combine the JRE and JAR file? Then I can be sure it works when I download it.


For the same reason you don't deploy Windows, BSD and Mac OS X binaries of your Go program to a Linux server.


Yeah I use the Linux binary, I'm not sure what you're saying here.


The JRE is platform specific, the JAR isn't. Bundling them makes little sense.


I think it makes a lot of sense. I can download the Windows version of an app and double click on it and it runs. As opposed to I double click on it and it's all "oh you don't have a JRE" or "you have the wrong JRE, mysterious error" or "you need to install this JRE", or it installs a JRE for me, but another app requires a different JRE.


I'm surprised you didn't mention Java compiles to byte code which is then JITed for the processor on which you're currently executing - I don't need to recompile for every platform and I still get native performance. This has been Java's primary strength since the introduction of JIT. Even better, I don't have to use Java to create the byte code. My favorite happens to be Clojure but you have several language options to suit your needs.


You never had any classloader issues with things like logging libraries and their configs or XML parsers? No versioning problems with dependencies of dependencies getting confused at runtime? No inconsistent clasloader behaviour with differnt Java EE containers?

I'm not saying that library versioning and dependencies are not a problem with Go. Quite the contrary. But it's a compile time issue. There are far fewer surprises at runtime and that makes deployment a lot easier.


    > You install a JRE on the machine. 
Whoops. That's where you lost me.


Fair enough. I certainly agree that Go is an excellent language for people incapable of doing basic stuff like this.


I'm perfectly capable, I just don't see the reason. Why should I install a JRE to run your program? The JRE has nothing to do with your program; it's incidental complexity. Go gives us a way to eliminate that incidental complexity and so is a step forward.


hmm, well we can dumb things down if you really need it. I think things are already pretty simple though.


I suspect this comes from classic Java setup of using an application container like weblogic, websphere, JBOSS or web containers like Tomcat.


> You install a JRE on the machine. You deploy.

That's two steps. The first one can ruin your day.


How so ? It takes minutes to install it.

Just download it, copy it and set JAVA_HOME to make it easier for other applications.

I've done this on hundreds of servers during my lifetime and never once had an issue.


Oh, look, there's already an antique jre installed on my os, not compatible with the particular jre needed by this application, which I first need to uninstall. And then hope that it doesn't break anything else in the process, because I haven't been following the minutae of java development environments for the last n+1 years...

I think it falls solidly in the "easy if you know it, and a wasted q hours if you don't" category.


That's why he said to set a JAVA_HOME so this JRE can exist separately from the system one.


I am not sure your definition of upgrade, but it is definitely a downgrade in terms of features even comparing it to Java. It has lean environment that makes it more attractive to systems programming and the CSP (channels, go routines etc.) make it great for concurrency. The trouble starts when you are shifting from systems projects to business logic projects. This is where Java runs circles around Go (or for that matter several other languages/environments). I wish Go had similar type system like OCaml.

https://functionwhatwhat.com/go%E2%80%99s-type-system-is-an-...

If I would like to teach something smart to software engineers I use OCaml, if I want to teach how simple things can achieve a lot I use Go. (They gonna end up programming in Java or Python anyways :)) )


I get the feeling that the people who deride Java either have little experience with the language and ecosystem or had were the poor folks that had to maintain a legacy <1.4 Java app for years and have no experience with modern Java.

It has its quirks (what languages doesn't?) but it is a fantastic general purpose programming language.


In my experience, Go is a lot more attractive as an upgrade from Ruby or Python. It's a very steep downgrade from Java on all points imaginable: type system, exceptions, genericity, garbage collector and runtime, tooling, IDE's, etc...


It's an upgrade in terms of compile times, deployment simplicity, conciseness, concurrency, etc. Some people care about such things.


Compile times are largely irrelevant if you use something like JRebel, Play, Tomcat or the many other frameworks that support hot reloading. And Java is far broader and more flexible at concurrency than Go with libraries like Quasar, LMAX Disruptor and the many HFT contributed ones.

Let's also not forget that Java is significantly faster, has every library under the sun, has a dependency system that actually makes sense and you have seamless interop between multiple languages e.g. Ruby, Python, Scala, Clojure.

Anyone who thinks Go is an upgrade to Java is woefully misinformed.


"Let's also not forget that Java is significantly faster"

Citations please. While I am not necessarily saying I don't believe you (because a properly tuned JVM is lightning fast), making a statement like this without numbers to back it up is a gaping hole in your argument.


As always, it depends on what you're measuring. I find it to be largely a wash

http://benchmarksgame.alioth.debian.org/u64q/go.html

Keep in mind this is comparing Go 1.4, I'd expect 1.5 to do better.


You say that, but because 1.5 is written in Go, it actually does significantly worse on some benchmarks and actual programs.

See: https://talks.golang.org/2015/state-of-go-may.slide#11


Note that the benchmarks game is going to count compile time against Java, but not against Go, since Go is AOT compiled and Java is JIT'd. If your app is a long-running server, you should take the benchmarks game numbers with a grain of salt.


JVM start-up, JIT, OSR etc take very little time relative to most of the workloads shown on the benchmarks game.

http://benchmarksgame.alioth.debian.org/play.html#java

The notable exception (not included in summary measurements) is the few tenths of a second run-time for meteor-contest. Of that few tenths of a second: JVM startup takes 95%, JIT and OSR another 4.9%.

Whatever kind-of app you have, you should take general statements about program performance with a grain of salt, there's even a page for that --

http://benchmarksgame.alioth.debian.org/dont-jump-to-conclus...


Keep in mind Go 1.5 has not been released yet :-)


Not the best but the Techempower one is one example:

https://www.techempower.com/benchmarks/#section=data-r9

And arguably more real world than microbenchmarks.


There are cases where the Go compiler generates horrors, and the only workaround is to write your code in asm.

Here's one example:

// imagine a for-loop around this

s := foo[i:i+4]

s[3], s[2], s[1], s[0] = s[0], s[1], s[2], s[3]

The reasonable assumption is that the second line generates either zero, one, or four bounds checks on s. However, the Go compiler likes to be sure, and turns it into 8 bounds checks.

I agree it's not a typical for a server to spend the majority of it's time swapping bytes. In the rare case that happens, you're going to hate the compiler for not being smarter.

EDIT: fixed formatting of the example


Some people like things that are minimal and good enough. Also, there is a huge swath of engineers who just really dislike writing Java.


Adrian Cockcroft does and I don't disrespect his opinion even though I'd far rather functional languages won the developer mindshare myself.

We shouldn't be under-selling how light the Go footprint is. In the long run it may be one of the few languages to compete with unikernels.


> In the long run it may be one of the few languages to compete with unikernels.

Can you please clarify what this means? I don't really understand what it would mean for a language to compete with a unikernel.


Most of the benchmarks I have found show go to be faster at cpu things and java to be faster at memory things.

This is no surprise considering that go is a compiled language and the java garbage collector has had decades of very smart people working on it.


   > It's an upgrade in terms of compile times, deployment simplicity, conciseness, 
   > concurrency, etc. Some people care about such things.
I remember the days of going for coffee while the compiler chugged away but I wonder what compiles people do on a regular basis that take such time? I just rebuilt SBCL here on a mid-2012 MBP and it took less than 6 wallclock minutes in the background including download and whatever else I was doing:

   real	 5m12.752s
   user	 4m33.393s
   sys	 0m27.579s
I personally use D when possible, but waiting on compiles is usually secondary to the amount of time I spend thinking or exploring.


> IDE's

Lack of an IDE is a feature not a bug.

Edit: or it is a symptom of a feature. No one has written one yet because they are happy with what they have.

> tooling

Do you mean you need an IDE that speaks the language to write anything efficiently? Do you mean your first day on the job is spent setting up tools?

Wrong philosophy in my opinion; I could imagine something better.


Depends the definition of IDE. My IDE is VIM. Why is it an IDE? Because it understand the text I am editing. An editor does not understand it. Anything, that supports programming on the top of an editor an IDE feature in my view. If you definition of IDE is IntelliJ than it is a different problem. I cannot edit Java without it anymore, Java is just too verbose and too many things can go wrong, I need immediate feedback from my IDE to tell me that I am doing it wrong also collapsing too verbose parts is a great thing. I don't use too much of IDE features but anything that I incorporated to my workflow over the years (very little, I keep it simple) is damn useful and I am pretty sure I would be slower without it.

Languages with small clean syntax do not require that much IDE usage, at least this is my experience. I never thought my Erlang workflow could be improved with something like IntelliJ. I guess having a REPL helps a lot.


Having tools that can spot errors early, help you track them down quickly and help you comprehend, organize and refactor your code can be very useful with a large codebase, and I don't think it's fair to characterize that as "you need an IDE that speaks the language in order to write anything efficiently."


Like gosublime?


Yes, Gosublime is a good example of how tooling can be helpful, though from what I can tell it is somewhat less helpful than what you'd expect in a decent IDE (e.g. no refactoring support, the interface is mainly dropdowns, weak support for finding definitions and usages).


Really, all I need is gofmt on save, and even that is mostly because I've gotten so used to it that I drop ugly unformatted dreck into my editor and let gofmt clean it up.

I worked full time for year without go to definition, mostly because full text search is almost as good most of the time, due to how regular formatted go code is. I don't really use anything else, mostly because I don't need anything else and I have better things to do than install editor plugins.


I really don't get the amount of love for gofmt. It's a formatter. wow! amazing! That's never been done before.


Yes, but it had the One True Format, which is the only way it can possibly work. I've used a formatter at other jobs in other languages, and you end up having your formatter fighting with everyone else's, unless they're configured exactly the same, which no one can ever agree on.


It takes me about 5 minutes to setup IntelliJ. And that includes the download.

And I would never want anyone in my team who was doing major refactoring work without an IDE.


In some ways, this is correct. Go is much more simple and consistent than Ruby or Java, has a better deployment story, and better tooling in some ways.

As a language, it's much less enjoyable to write. Yes, the concurrency primitives are much better, and that's a good programming tool. But to a developer coming from Ruby, code is often needlessly repetitive and obtuse to write. It ends up being overly verbose, full of copypasta, and much less expressive.

It's got it's niche – I've found it useful for writing small command-line utilities, and it's been surprisingly helpful at putting together a good deploy story for some work I've done on the Raspberry Pi (with the benefit of being well-structured and reasonably performant).

But I wouldn't like to use if full-time – mostly because it's just so weirdly irritating to write.


"code is often needlessly repetitive and obtuse to write."

I think it helps to remember that Go's use case is a lot of teams interacting to produce fairly large code bases, i.e., at Google. I'm getting into it for my job because it has the same use case, and I find it hits a nice sweet spot in what you can do, vs. what you can't do, and I happen to be in a position in which I am routinely hit hard by other people's "clever" code. I don't do my personal coding in it, though.

Part of the problem with the "clever" code is that it often uses the clever features, but, wrong. Like, all the pain of seeing someone do something "clever"... and you'll note how I keep scare-quoting that... and none of the benefits. If the clever code was actually more concise and performant than my generally-non-clever replacements, I wouldn't mind so much, but it's amazing how often I rip out a "fluent" API or something and replace it with something simpler, faster, and still results in several hundred negative lines on the commits.

I've developed a theory that it isn't even because the developers are "dumb" or something, especially since in many cases they manifestly are not. I think it's that once you pass a certain size of organization, but are still sharing some code bases, you encounter an increasing number of instances where a developer has to fix something in the shared code, parachutes in to make the minimum possibly change that might work with the minimal cognitive effort, and gets out and back to their own code as quickly as possible. The net effect in such situations is that even if your code is being written by nothing but senior devs with decades of experience, from the point of view of the code being developed on it might as well be being bashed on by a series of above-average gorillas bashing away on keyboards.

Languages that tend to point you at a single right answer, and confine the very busy, very distracted gorillas from beating on the code too hard, and make it obvious when that's happening, can be advantageous in those cases.

No, that's not every case, but it's a useful one.


The Java approach to larger-scale programming.


Which, uh, has been very successful for java.


Uh, um, did I say that it hasn't?


I wish there was a language somewhere in between Ruby/Python, Elixir, and Go.


Have you looked at Nim?


There's also Crystal (http://crystal-lang.org/).


Wow, thanks for the pointer. This looks like a sweet almost-ruby like language.


I like Nim a lot, though you still need to know C for edge case issues.


> And compared to Java, the fact that Go compiles to a native binary is a huge benefit.

Java has multiple native code compilers, how is it a benefit when Java can do the exact same thing? (FWIW I learned recently that C# also has at least one native code compiler).


One option with C# Windows Store apps is that they can generate native code using something called ".NET Native". https://msdn.microsoft.com/en-us/vstudio/dotnetnative.aspx


I could be wrong, but I feel like when people talk about how great the Golang tooling is, what they're really saying is "the compiles are instantaneous". I'm sure he's right that the coverage tool isn't 100% perfect, or even 60% perfect. OK. Fine. The compiles are instantaneous. Write a better one!

Golang is not an especially impressive programming language --- as a language. But it seems to me like it is an undeniably impressive programming tool.


>I'm sure he's right that the coverage tool isn't 100% perfect, or even 60% perfect. OK. Fine. The compiles are instantaneous.

Since when was compile time an interesting aspect to judge a programming language? More in the "nice to have" category, especially if your program is not 1 million lines and/or your language's compiler doesn't provide some modularity in this regard.


He is not talking about a "programming language", he is talking about "programming language tooling". So yes, compile time is an valid and interesting aspect to judge a programming language tooling ever since the beginning.


> Since when was compile time an interesting aspect to judge a programming language?

Since compilers were dog slow.

When using irb or lisp or smalltalk, my productivity is off the charts compared with C++, in no small part to the compile time.


Where do you think the Turbo in Turbo Pascal comes from?


Have you ever worked on a large-scale C++ project?


Actually, the biggest problems with large-scale C++ projects for me have been "long compile times for fully optimized builds" and "long linking times", neither of which Go 6g/8g solves.

Put another way, much of the problem is "modern compiler optimization takes a long time". Go's solution was "remove the modern optimizer". That doesn't actually solve my problem.


No, but then again, as I wrote in a comment just above that one:

"I don't think most teams outside of Google and some C++ or Scala shops have had any issue with "long compile times" for that to have been a major factor."


I completely agree. Some languages are written to adhere to an ideal (everything is lists), and make sacrifices in order to stick to that ideal. Some are written to be close to the metal, or to be as abstract and flowery as possible, and make different sacrifices. Every language has some primary goal, and all the rest must bend to accommodate that goal.

Go's primary goal is: excellent tooling.


except for, apparently, poor code coverage tools?


The coverage tool is fine. He didn't really explain the problem well. Coverage is per package, and only counts coverage from tests in that package. This makes sense because packages are independent and you can't count on another package to test yours.


Funny how HN was on the Go bandwagon just a few years ago, and now an article like this is almost unanimously upvoted (without much contrarian discussion(!)).

I contributed to Go in the early phases and I really enjoyed using it and learning it, but I found myself going to either Java if I wanted to write something for production or Node if I wanted to write something as a prototype. Unfortunately, I haven't used it almost at all for the past couple of years :(


Go has always had quite a mixed reception on HN, even if articles about it ostensibly are part of a voting trend.

Generally, trying to approach Go from any perspective related to PL theory is bound to be fruitless, primarily because the context of Go is that of Rob Pike's gradually evolving research languages, which have always been imperative, based on a few primitive constructs and having some form of CSP-like concurrency model built in. Much of it overlaps with principles explored in Plan 9 and Inferno, where holistic systems thinking has been the norm, and so Go makes sense as a language built by systems hackers used to dealing with infrastructure, rather than being conjured from the academic PL scene.

Much as Alef superseded Newsqueak, so Go has superseded Limbo.


I think you'll find that opinions that trash talk any given technology whether OS, browser, language, editor, hardware, etc and then take the easy way out by not posing the "correct" choice get heavily upvoted.

In general, it's much easier to spot defects and more difficult to see the good in things. People are much more likely to play into their own biases from the safety of online anonymity.

For instance, "I don't like this OS, browser, language, editor, hardware, etc or this person's/company's choice of OS, browser, language, editor, hardware, etc, therefor downvote/rant/complain/FUD."

It's really too bad. It never hurts to know more, and it shows new members of the community that it's acceptable to behave that way and to not try to learn new things.


I still like Go, but the Go discussions on Hacker News aren't that interesting anymore.


Most Gophers just get tired of defending against the same arguments over and over.

At least this guy actually used it for more than an afternoon... Though anyone who says they don't understand go's pointers after that length of time is a somewhat questionable source.

I've been using go full time for two years and love it.


> Most Gophers just get tired of defending against the same arguments over and over.

Tip: you're not required to be a defender/evangelist.


HN was the same about Node too. In a year we will see the same articles about Rust.


See also: AngularJS, Rails, etc. A lot of this is just because things that a technology makes convenient fade into the background after awhile because you know longer feel the pain you felt before you had them, but you are actively reminded of the things that annoy you about a technology multiple times a day. For example, with Go, fast static compilation and "just works" deployment fade, while the copy-paste-tweak pattern for generic behavior continues to bite. For Angular, you start to forget how much easier it made defining modular view components and having up-to-date data everywhere, while actively finding complexity and performance frustrating.

I'm sure you're right about Rust, and that people will be down on lifetime annotation burden, painful compilation times, painful data structure nesting, the complexity of unsafe code, and other things, while forgetting all the times things are actually easier, more performant, and safer due to all that language support.

I see it as a natural damping curve: at first things seem peachier than they really are, then they seem much more frustrating than they need to be, then you come to terms with their unique trade-off of strengths and weaknesses. What I would like to know – if anyone here has discovered such a thing – is a way to skip to the last step more quickly.


As I get older and I gain more perspective, I can't stress enough how true this is. Listening to younger programmers bemoan Ruby and Rails is humorous to me because they don't remember the world of Java web dev before Rails. Miles of XML configs everywhere, factories, impls, proxies, beans. So. Much. Boilerplate.

It's easy to bitch about things the way they are now, but understand there are people and technologies who were around before you arrived on the scene and in general, things are consistently getting "better", for all subjective interpretations of "better".


so what you are saying is, we should be fine to whine and complain because something better is coming.


Yes, then we can move on to whining and complaining about that.


Now I'm confused. I've heard that we should learn and appreciate that nothing is new under the sun and most interesting concepts and technologies have already been invented in the past and not newly by newer technologies. Now you're saying that newer technology consistently improve things? I'm getting confused as to how the older hive mind is telling me to feel.


Concept and implementation are not the same thing. The concept of LISP hasn't changed in 50+ years, but the implementations have been constantly improving the whole time.


> I'm getting confused as to how the older hive mind is telling me to feel.

Maybe that means it's not a hive mind? Different people have different views, I suppose.


There's an entire Wikipedia article on this concept, in fact:

http://en.wikipedia.org/wiki/Hype_cycle


Thanks for the link – an enlightening read.


The thing you want is called "getting old". You realize the benefits of certain things and know about the weaknesses before they are even brought up. Sadly this can't easily be taught - it is just slowly learned. And yet us old farts continue to be shunned in many parts of the industry (perhaps because we are grumpy old curmudgeons who have seen it all before).


I think programming languages can bring new things to the table. For Go that's M:N userspace threading combined with a shared-everything mutable memory model in a high level language. For Rust, it's memory safety without garbage collection. For JavaScript, it's the event loop model. Those crucial differences make languages usable for unique niches where you won't want to use anything else.

Unfortunately, most of the debate around languages involves "philosophy", where there's little objective measurement that can be done: composition vs. inheritance, the effect generics have on readability, whether immutability is a better way of reasoning about data, whether namespace syntax should use double-colons or periods, and so forth. These debates are endless but don't strike me as very useful: the exact issues that get brought up and argued on HN have been going back and forth largely since the '80s if not earlier, and they're neither interesting (because we've made little progress on consensus) nor relevant (since people who actually need to choose a language based on its merits will choose it because it helps their job, not because of philosophy).


Are you bitter that people "don't like" Node any more?


It's typically not a good idea to choose technology based on fashion. If you like what Go has to offer, it's there for you to use, and don't let the hype backlash get you down. Maybe start with a small personal project, if you don't want to commit to working with it "in production."


The problem is that trying a language isn't like trying a new restaurant. At a new restaurant, I'll know within an hour almost all I would know after a year, and my chances of misjudging the restaurant that first hour are both low ("Hmm, none of these dishes taste very good to me, and I'm not wrong about that") and of minimal consequence (maybe there are better dishes I missed, or not, but I can just try a different new restaurant tomorrow.)

But my first project in a new language will take more than an hour (well, "hello, world", but that won't be enough of a test), and after I find something I don't like about the language in a first project, I've either found something bad about the language or something bad about me that this language is going to cure. Which is it? How will I know without an even bigger project...and pretty soon I'm the OP having spent a year giving the language a fair trial and now needing to start over with another language for another year.

I have a lot more hours left to investigate restaurants than years to investigate languages.

So, it's not a question of "fashion" per se, but trying to learn from the experiences of others. Of course, "others" vary, but you can still learn a lot about things that wouldn't be obvious to you in a first project by reading a lot of those varied opinions.

I read a lot about Go that interests me, but I just saw a survey of several thousand back-end mobile developers that showed that now, after several years of availability and the Google connection and all the talk about being a better Python and its explicit positioning as optimized for server-side apps, Go was not among the Top 8 most used languages for server-side apps. That interests me, too.


I agree with you that there is value in these varied opinions. I think it's part of why this sort of post tends to get upvoted regardless of whether it is positive or negative about the technology.

In his blog post written roughly a year ago about his first week using Go he says this:

> gonna be dealing with Go for a while and will have to make the best of it.

I could be wrong, but I get the impression that if it were solely up to him the project might have been written in Erlang either from the start or after trying Go for that first week.


> now an article like this is almost unanimously upvoted (without much contrarian discussion(!))

The HN guidelines were changed (or defined more precisely...) and many people might shy away from posting negative comments about submissions.

I have to compliment the author on omitting complaints about lack of generics.


> if I wanted a language built around concurrency I’d use Erlang or Haskell.

And if you wanted a concurrent language that wasn't a functional language what would you use?


Or just a practical concurrent language with strong libraries that lets you be productive quickly. I'm aware of many of the theoretical benefits of Erlang and Haskell over Go. But Go is still a much better choice for getting things done.


As someone who used Go in the past for work and now uses Haskell, I can say that the advantages of Haskell over Go are more than "just theoretical".

In my day job I use Haskell to "just get shit done". However when it comes time to refactor I can do it much faster and safer in Haskell.

The ease of refactoring creates an incentive to improve code.


Seems like Go and other imperative languages are easier to start a project off with, but functional languages really shine when the code becomes really large and complex.


I can agree with that, but once you are experienced with functional languages I think "easier to start off with" becomes a very low value. I'm assuming by start off with you solely mean "starting a new project" and not "starting to use language from scratch".

At least that seems to be what has happened in my case.


I find that the confidence that refactoring will be easy helps me tremendously with velocity when starting a project.


My experience is the exact opposite. Maybe we work on very different kinds of problems, or maybe it's just because we're different people.


> Maybe we work on very different kinds of problems, or maybe it's just because we're different people.

In the interest in figuring out which, what problems do you work with and what are your principles/beliefs/guiding principles in software? :P


I work on rest APIs mostly and the Internet of things.


C# has had excellent concurrency support for quite some time, and is most definitely a utilitarian language.

Of course, the elephant in the room is needing a windows-based infrastructure ... but if that's not a huge barrier, it's not an unreasonable choice.


I keep forgetting about C# and F#, but with Microsoft embracing open source they may become actually interesting for people outside the windows world.


It might not be common knowledge yet, but C#, F#, and .NET are fully open source and cross-platform. Development is done in public on GitHub (https://github.com/dotnet), and pull requests are accepted from the community. You can even get a support contract from Microsoft and call them up to troubleshoot your .NET project on Linux. No Windows required.


Other languages like Clojure, Python and even Javascript are catching up to Go and are adding decent support for concurrency too. But I would definitely prefer a functional language for a project that involves a lot of concurrency. "not a functional language" is a weird requirement.


Are you talking about Clojure? :) I am not sure what is the fuss about functional vs. imperative, you can do both in Clojure, both ways have a place in the programming toolkit. I think about functional programming as a philosophy. Nobody is going to despite me if I use swap! in Clojure or I use a mutable variable. On the other hand even when I am in an imperative environment I tend to use functions that keep the state in the parameters so the state is explicit and visible rather than a hidden something inside a class.


Yes Clojure, sorry about the typo! The difference is that with Haskell or Erlang you get hard guarantees about side effects, but access to imperative libraries is very difficult. So you are kind of locked in a small ecosystem.

With Clojure, Scala or F# you need to be disciplined and don't really get many guarantees, but you can reuse lots of imperative code.

It kind of depends what your priorities are, if it's correctness or development speed.


> The difference is that with Haskell or Erlang you get hard > guarantees about side effects, but access to imperative > libraries is very difficult.

Well yes, I can just live without imperative libraries because it is so natural to have single assignment (in the same scope) that I do it even in other languages. Accessing imperative libraries is possible though, just think about the C libs. What would you implement in Erlang the imperative way or which library do you miss exactly? The ecosystem is definitely smaller, but you can get support, some of the smartest software guys hang out on the mailing lists and IRc as well. I got absolutely amazing help from both when we worked on a Erlang project.

> It kind of depends what your priorities are, if > it's correctness or development speed.

Yeah and also how much fun you want to have. :)

Using Erlang is great but not many devs out there for hire, on the other side you have two seasoned Erlang devs they can do a lot. Contractors FTW!

Btw. what about using ASN.1 with Erlang? How does that change the correctness / development speed?


> The difference is that with Haskell or Erlang you get hard guarantees about side effects, but access to imperative libraries is very difficult.

In my experience creating Haskell bindings to say imperative c libraries is pretty easy. What imperative libraries have been hard to access for you personally?


> The difference is that with Haskell or Erlang you get hard guarantees about side effects

As far as I know Erlang doesn't give you any guarantees about side effects. You can call side-effecting functions at any point in your program, just like in Clojure or OCaml.


Python is my longest standing favorite language. But after working on a large python project I am cured for life of dynamic languages. I would not use them for anything over ten thousand lines of code ever again if I can help it. Go is now my favorite language.


>But Go is still a much better choice for getting things done.

What makes you say this?


Experience. I still don't quite understand it fully, but I'm much more productive in Go than any other language I've used, and I have deep experience in about 8 popular languages and passing experience with another 12. I can list things that contribute to that, but a list of ingredients does not equate to a culinary masterpiece. Other people's experience may vary.

Being a "boring" simple language with limited options for implementation means more focus on the problem and less on the infinite number of ways to solve the problem "elegantly". But there are a lot of other factors too. Static typing helps once the code base gets above 5000 lines, for example. Fast iteration from making a change to running the tests again also helps.


Maybe you should write a blog post and list those reasons and post it here. Would probably create interesting discussion.


Reasonable question,seemingly phrased without ill intent. Do not understand downvote.


This is what I think (hope?) Elixir could be: a bit more practical (familiar? convenient?) language with the same concurrency support as Erlang. Maybe after another couple years of maturing libraries.


Erlang is probably the only true object-oriented language.

http://www.infoq.com/interviews/johnson-armstrong-oop


> Erlang is probably the only true object-oriented language.

And it's true because its creator says so right here, in this link!


Or because it does satisfy much of the Kay criteria for OO and encourages such programming styles.


Nobody follows Kay's definition of OOP.

And I bet you're going to say "But he coined the term!". Yes. He's still making up his own definition twenty years after the industry gave its own, so whatever he says on the topic is moot.


Several things to note here.

Firstly, I don't know at what exact point did Kay come out in demystifying OO (1998 or so?), but the design principles of Smalltalk and messaging date back to publishing in 1974, with many references to it afterwards.

Secondly, the idea that there is one singular definition of OO that the industry has standardized on is absurd. Object models differ semantically from language to language, even if some general motif of "encapsulation/inheritance/polymorphism" is present (though again, important subtleties abound - is encapsulation enforced or merely convention, how structural and nominal subtyping are modeled [mixins], etc.).

But would you say that's the definition of OO? In fact, Kristen Nygaard who was the creator of the Simula language, an ALGOL extension, and now considered to be the first OO language (semantically in that it beefed up structs and other procedural nuances) considered object orientation to be a property of any system in general as opposed to language constructs. Thus, Erlang definitely does count as OO under that, too.

So what definition do we follow, then? Who do we trust?

Apparently this is a difficult problem: http://c2.com/cgi/wiki?DefinitionsForOo

But by all means, Erlang embodies many OO design principles by certain important taxonomies - both Nygaard's and Kay's. If you're going to reject both, then you're going down murky waters.


> But by all means, Erlang embodies many OO design principles

That's interesting because Armstrong himself thinks that OO sucks:

http://harmful.cat-v.org/software/OO_programming/why_oo_suck...


Probably Java (or other JVM lang) running something like Disruptor for high performance, or actor based libraries like Akka for general use case. No numbers, but considering how it's used in nearly all the bigger tech and finance companies, I'm guessing it probably has more use as a highly concurrent platform than anything else discussed here.


Another reason for their usage of the JVM could be because a lot of these languages specifically designed for concurrent programming either didn't exist or were in their infancy of real-world usage. Erlang was proprietary until 1998, and Haskell was not created by a large company. In the meantime, Sun was pushing Java everywhere they possibly could. So it makes sense that larger tech and financial firms, especially those who established themselves in the late 1990s (or descendants of such companies), would use the Java platform. There were also a lot more Java developers than Haskell developers, and there still are, and that's a big part of the decision-making process when choosing a platform.


Forget familiarity, hot code loading, and the huge library ecosystem (the largest in computing history) compared to one of the tiniest, but Java's runtime monitoring is far, far ahead of anything Haskell (or any other language or platform) can provide, and while Erlang's is pretty impressive (a close second), it is still not on the same level as Java's.


The standard JVM's don't support lightweight threading (like Go's Goroutines)...so yeah while you can do concurrency with callbacks, or "actors" (callbacks with lipstick on), it's not quite the same thing.


You can use Quasar, which does bytecode instrumentation.

http://docs.paralleluniverse.co/quasar/


The point isn't about learning something new. It's about trying to apply those things into a language they think is easier to work with.


I'd argue the point is the opposite of learning new things. As the Go team themselves say, Go is an engineering project. It's about sticking to well understood, well defined ideas that allow large teams of typical skill to develop and maintain good software. Go is boring compared to some other languages that push the envelope and try new things. But that can be a good thing if you start thinking like the business owner instead of a code monkey.


Most people won't see it this way, but not pushing the envelope is a new thing.


The problem is that Go doesn't use things which are well understood and well defined now (or were so 6 years ago when Go was released), it stopped its (partial collection) about 40 years ago.


If backend programming was epic fiction, then right now, the world is divided into the following countries: The Kingdom of Java, The United Languages of .Net, and the Confederacy of the Scripting Tongue (where racial tensions are crackle under the temporary truce between Ruby, Python, Javascript, Lua, etc.). For the past decade, these three kingdoms constantly struggled against each other for the most precious resource of all: developer mind-share.

But what they didn't know and couldn't prevent, was that their world would soon become (neigh, has already become) the battle ground of 3 ultra-advanced warring alien species: Go, Rust, and Elixir. Backed by unimaginably powerful forces (except Elixir, which is just open-source by Poland's own Jose Valim), the upstart alien languages threaten to herald in a terrifying future for the current 3 powerhouses.

OP's article, and the fact that lots of people are agreeing, is a sign that one of the invading aliens is weakening.


I want to watch this movie.

What about Pony?


What's confusing about Go, in comparing it to other languages, is that it's a minimum orthogonal refactor of a language. It was born out smart engineers observing the web and other languages for decades and thinking that they needed something low level but high level enough. It's built staring precisely at the past two decades.

C, C++, Java, Python, and an appreciation of formal specs over frameworks form Go.

Most languages to perform professionally in you have to know what not to do (not use C++ templates too much, not give into verbosity in hierarchies in Java, not use the GIL, etc.). In Go, because it is a relatively clean refactor, you don't have to worry about this.

But you do have to invent your own smaller libraries for what you want to do sometimes. Because it's a younger language. This is good though if you like programming and stacking lego pieces on you way to stacking paper.


> Good languages help evolve your approach to programming

Go certainly taught me quite a bit about closures and programming to an interface.


I think a lot of us miss the Go point.

There is nothing special about Go. It's simple and just works.

Every time I used Go for a project it just worked. No fuss. With very little effort. And that's the point.


But that doesn't answer any of the (very valid) points raised in the article?

Go is interesting as a replacement for a scripting language, perhaps. But it seems very lacking in many other areas. All of the points in the article, plus what libraries are available.

I think some of it could be explained by it being a young language, but if that's the case, why is it getting the adoption it has so far? Just because it came from Google?


Because it has allowed so many of us to significantly raise the ratio "Amount of time I care about my project"/"Amount of time I care about something other than my project (typically, the language itself)".

Go is the poster child for Worse is Better. It's ugly, inconsistent, feels naughty at times (all those copy-pastes ! It's so un-DRY !) but it gets shit done.


I've had a keen interest in go but haven't used it for anything serious. My impression of it is that its a great replacement for languages like Python and is great at getting things running fast but I have to agree that it doesn't feel like the kind language I wouldn't want to write a large code base in. My huge interest in it is around the single binary deployment and its concurrency model. The language itself I find a bit quirky in some places (some data structures are passed by ref while other by value) and I like my languages concise and elegant.

This post got me to have a second look at Elixir and I spent the whole day going though its documentation and prototyping an idea I wanted to implement in go, specifically because of go's concurrency model. And frankly ELixir is exactly the right fit for me, not only for this case but generally as a language with the kind of elegance and expressiveness I'm drawn to.


I always find it's difficult to navigate Go repositories on GitHub. Because there can be several source files under a package it's difficult to look for an implementation of a function or method. For Java, I can easily guess where the methods are by looking at import statements.


I friend of mine wrote a tool to fix that. See http://gotools.org/github.com/kjk/fofou for example (just prepend http://gotools.org/ to any Go import path).

Then you can use Ctrl-f (Cmd-F on mac) search built-in browser to look for things.

It doesn't work for large repositories but most of them aren't.


godoc is very helpful for this. You can click on the name of a type or function and it will take you to the definition.


> "I just don’t understand the point of Go. If I wanted a systems language, I’d use C/D/Rust, if I wanted a language built around concurrency I’d use Erlang or Haskell."

Agreed. C and Rust are systems langauges, Go is not particlarly great in that category. That is okay.

I will say, I hope you have fun getting an average CS graduate to properly write and maintain a Haskell or Erlang program with concurrency. Go is stupid easy to pick up for anyone who has worked with C/C++/C#/Java/Python/Ruby, which, by no exaggeration, probably encompasses every programmer alive.

Meanwhile, Haskell and Erlang look like gibberish to most programmers. And I'll admit, that's a lacking argument. Functional languages cannot be said to be bad just because most people don't understand the functional paradigm.

But the fact remains, an average programmer can sit down today with no knowledge of Go, and by the end of the day create a concurrent program using Go. And given the lack of flair in go, it's the langauge that lends itself to being maintainable. You won't see anything like in python or perl where you're almost expected to abuse the langauge internals (see this awesome example in python [0]). That's completely by design. [1][2] (scroll up to see the quote by Rob Pike)

If you have a team of a dozen guys working on a project with thousands of lines, your priority is not just performance (Go is quick enough [3]). It's probably not elegance either.

It's software that documents itself.

I used to work as a systems administrator for my schools engineering department. We would deal with fixing perl scripts dating back to the 90's. As students came and went, the result was hack jobs on top of hack jobs by students who are now in their 30's. I hated it. I would commonly have to rewrite scripts because over the years the basic flow of the program became completely asinine.

That's exactly where go does well. Go is a langauge for people who don't want to have to deal with abuses of the language that their coworkers put in place. Go is a language that understands that for programmers, maintaining code means fixing bugs and fixing bugs tends to boil down to hacky solutions. Go ensures that those quick fixes aren't hacks.

> "The only place I can see Go shining is for stuff like portable command line utilities where you want to ship a static binary that Just Works(tm). For interactive tasks I think it would be fine, I just don’t think it is particularly well suited to long-running servery things."

I really don't understand why he feels that way. I don't see the distinction.

> "It also probably looks attractive to Ruby/Python/Java developers, which is where I think a lot of Go programmers come from. Speaking of Java, I wouldn’t be surprised to see Go end up as the ‘new Java’ given the easier deploy story and the similar sort of vibe I get from the language. If you’re just looking for a ‘better’ Ruby/Python/Java, Go might be for you, but I would encourage you to look further afield."

This reminds me of The Story of Mel [4].

If you're someone who enjoys programming and are writing the code for fun, I agree. Find the most unique language and do it in the most elegant way. Programming is almost an art, and if you're trying to be artistic, unique langauges are great for it.

But not all software is artistic.

> "Good languages help evolve your approach to programming; LISP shows you the idea of code as data, C teaches you about working with the machine at a lower level, Ruby teaches you about message passing & lambdas, Erlang teaches you about concurrency and fault tolerance, Haskell teaches you about real type systems and purity, Rust presumably teaches you about sharing memory in a concurrent environment. I just don’t think I got much from learning Go."

I don't think that all langauges need to be learning experiences. Sometimes you just need to get shit done.

[0]: https://benkurtovic.com/2014/06/01/obfuscating-hello-world.h...

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

[2]: http://nomad.so/2015/03/why-gos-design-is-a-disservice-to-in...

[3]: https://benchmarksgame.alioth.debian.org/u64q/go.html

[4]: http://www.catb.org/jargon/html/story-of-mel.html


> But the fact remains, an average programmer can sit down today with no knowledge of Go, and by the end of the day create a concurrent program using Go.

If there's any benchmark more pointless than the alioth benchmarks game, it's the 'what can a novice programmer do with the language in the course of 8 hours' benchmark.

There are zero businesses that operate by giving novice programmers 8-hour tasks in unfamiliar languages.


The first company I was at prided itself on the "sink or swim" method of hiring. You'd be surprised how many developers out there judge new hires by how quickly they show they can start shipping code.


It's the wrong approach, but it does happen.


>> If there's any benchmark more pointless than the alioth benchmarks game… <<

Just name-calling, ho hum.


> You won't see anything like in python or perl where you're almost expected to abuse the langauge internals (see this awesome example in python [0]).

You linked to someone intentionally trying to obfuscate Python as much as they can. Programmers are certainly not "almost expected to abuse the language internals". All dynamic languages provide various means for code obfuscation... it doesn't mean the language encourages obfuscated code. With the notable exception of Perl.


Fair point. It does not encourage it.

But it does allow it, and I think that means it inevitably creeps into a lot of code.


Strongly disagree. It is actually much harder to write obfuscated code in Python than in C. It even enforces whitespace... Here is "Hello World" obfuscated in many languages: http://codegolf.stackexchange.com/questions/22533/weirdest-o...


I have never once seen anything approaching obfuscation in any "serious" Python code.


Depends on what you consider obfuscation. Consider the following python code:

  a.b = c
In isolation, there is really no way to tell what that line of code will do. Maybe it will simply assign c to a.b. But because Python has property setters, it might also update some rows in a database[1], write a file, or make an HTTP request.

One might call that abstraction, but I think it qualifies as obfuscation. A single line can invoke arbitrary behaviour.

[1] This is how SQLAlchemy's models work. As I write this, the library is nearing it's 10,000th commit. A serious piece of software!


> A single line can invoke arbitrary behaviour.

Isn't that true of any language with even the simplest mechanism for abstraction?

How about this go code?

    doStuff(1, 2)
It could "update some rows in a database, write a file, or make an HTTP request."


I think that's fundementally different, you know you're calling a function there.

An example in golang would be something like:

    type foo struct {
        a    string
        b    int
        c    *someOtherStruct
    }
    var blah = foo{"example", 42, nil}
    blah.b = someMagicVariable


Sounds like your issue is with operator overloading. The same can be done in C++ and any other language with operator overloading.


When I use Rust I am constantly annoyed by how limiting traits are in comparison to interfaces. I much prefer interfaces, which are a single type, as opposed to traits, which are sets of types.


I don't see how traits are limited.

Traits are types, though you need to put them behind a pointer (Box<Trait> or &Trait) if you want to use them as types; and this is dynamic dispatch.

You can use them in static dispatch (generics) too, and in general you should try to do that whenever possible. Plus there are loads of things you can do with them that Go can't (static trait methods, associated items, generics, etc)

The only feature that Go interfaces have that Rust traits don't is auto-implementation, and that's a misfeature IMO. It works okay for Go, but in Rust it makes more sense to explicitly say that you are implementing a trait.


What do you mean by "sets of types"? Traits in Rust handle more duties than interfaces do in Go, but in their role as interfaces the only difference is that Rust traits are explicitly implemented whereas Go interfaces are implicitly implemented (i.e. nominal types vs structural types).


Take the following example from Go:

    type ExInterface interface { ... }
    type ExStruct {
         arr []ExInterface
    }
Each element of arr need not be the same type, so long as it implements ExInterface. In Rust, the only thing I can do that is similar is:

   struct<t: ExTrait> ExStruct {
        arr: Vec<t>,
   }
Which means that each element of arr not only has to implement ExTrait, but also has to be of consistent type with the rest of the elements. If I want the same level of flexibility the Go gives me, I need to make an enum of each possible type that arr can contain.


To elaborate a bit on the sibling comment here, Rust makes things a bit more explicit than Go does. A Go interface type is actually a pointer (of sorts), since you don't generally want to store things of different types and sizes in a single array. For example, if you have:

    type StructOne struct {
        field uint32
    }
    
    type StructTwo struct {
        field uint64
    }
It's pretty clear that these structures are of different size. Now, if both of these structures implement the "Foo" interface, we can't simply make an array like []Foo, since we'd have no practical method to index into the array. Go solves this by making []Foo actually be an array of pointers.

However, Rust's philosophy is, AFAIK, "be explicit about the cost you pay". So, if you want to make an "array of things that implement Foo", you need to explicitly put the "things" behind a pointer, or a Box<>. So, you get:

    struct MyStruct {
        arr: Vec<Box<Foo>>,
    }
Which makes it explicit that you're storing a "list of pointers to things that implement Foo". Of course, the nice part is that you can use generic syntax to make an array that doesn't use pointers, like so:

    struct MyStruct2<T: Foo> {
        arr: Vec<T>,
    }
In the above, you can only store items of a single type in the `arr` field, and the generics constrain that to be only types `T` that implement Foo. The upside is, however, that you don't have any pointer indirection (and the compiler monomorphizes - i.e. generates new code for each generic implementation), so your code is probably faster / easier for LLVM to optimize.


You can do that by storing `Box<ExTrait>` in your vector. In fact, that's the equivalent of what Go does in your example.


That's fantastic to know. I might just switch back to rust because of this.


If you have known lifetimes, you can also use &Trait (and lifetime variants thereof): http://is.gd/4SyShN

For more information on that, check out "trait objects" (http://doc.rust-lang.org/book/trait-objects.html).

The gist of the issue is this: a Vec (and most other collections) needs all items to be sized and of the same size in-memory to lay itself out (know how much memory to reserve for each item for instance), and it stores its stuff inline. So a Vec<u8>'s buffer looks like this:

    [u8|u8|u8|u8]
and a Vec for a struct { u8, u32, u8 } looks like this (ignoring padding):

    [u8,u32,u8|u8,u32,u8|u8,u32,u8|u8,u32,u8]
If you want to store both A and B inline in a Vec you've got trouble: that they both implement Foo doesn't mean they have the same size at all (and they often don't), and Rust's type system doesn't allow it anyway (`A: Foo` says that A implements Foo, but the function or collection still gets an A via reification and monomorphisation).

The alternative is to do what languages Java or Go do under the covers: add a fixed-size pointer as indirection between the collection and the actual items (the pointer is actually fat, you get a pointer to the instance itself and a pointer to the vtable for the trait implementation, I think Go does the same but java doesn't as each instance has its classpointer), so you get e.g.

    [&A|&A|&B|&A]
all pointers are the same size and things work out. More generally than trait objects, you need to do this to store any unsized type (http://doc.rust-lang.org/book/unsized-types.html) in something which only accepts sized types.


How do traits limit you? Could you give an example?


> Why the heck is Go making me care about pointers at all if it is a GC’d language?

Apparently, the author doesn't understand how pointers work in Golang. He should read this article: http://openmymind.net/Things-I-Wish-Someone-Had-Told-Me-Abou... . In short, golang pointer is neither c pointer nor java reference.


Go is great and all, but I'm really only using it until Rust is ready.


Rust 1.0 came out recently. What are you waiting for?


Complete, stable and mature standard lib.


What are your criteria for "ready"?


Sweet, I'll stick to learning Elixir with some (Erlang)!


[deleted]


I totally agree (except for the new-grad conspiracy.) I use Go whenever I need to do something small that requires a simple server or API interaction. Especially if it requires alot of concurrency. It's still a joy to use when I need to get something churned out quickly. The biggest thing it gave me though, was something new but accessible that wasn't Ruby, Python or JS.

It made me think about pointers, and gave me insight to just how complicated strings and growable arrays are under the hood instead of just being givens like in Ruby. It simplified concurrency and parallelization enough that I was able to dive in and learn the concepts which I was then able to use to dig deeper with other languages that don't have the nice channels/select built in.

I've come to realize that, in my learning at least, there are thresholds of information that people get stuck at, but once they cross you get a flood of improvement. Go allowed me to stop thinking only within the code context, but also in the machine context. Now a large amount of my side projects are in C or Rust, and even my day job writing higher level languages has benefited greatly from the new ability to understand the moving parts. It's not going to give you a compsci education, but it'll give you that intermediate step you need to wade into that territory.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: