Hacker News new | ask | show | jobs
by api 2230 days ago
I love Go for this reason. It minimizes it's own cognitive load, freeing the mind to spend more time thinking about being clever solving the problem rather than being clever with the language.

I also adore goroutines and miss them in any other language. They are really fibers and let you do light concurrency without fiddling with async constructions. Async programming is just an ad hoc way of implementing fibers, and it imposes more cognitive load because now you have two different approaches to every problem in the same language (one async, one not).

IMHO minimizing language-imposed cognitive load should be a core goal of any programming language. Human brains are finite, and programmers should spend the majority of their mental energy thinking about the problem being solved not the language.

1 comments

Unfortunately a substantial number of people seem to suffer from a type of concurrency Stockholm syndrome. They prefer explicit and awkward concurrency constructs, perhaps because until Go, mainstream languages like JavaScript, C#, and Python implemented hacks largely because of implementation constraints, so it's all they know. They say thinks like, "I prefer knowing exactly when I might block". Yet you never hear them bemoan the fact that the OS hides process scheduling and VM paging; they don't complain that they can't hook into this at all, let alone be forced to do it 100% of the time for even the simplest code. They never ask that their language force them to be explicit about how and when a simple function call will setup a new stack frame. All of these things were, decades ago, the equivalent of fibers (or more generically asymmetric stackful coroutines). People were likewise skeptical about those things, but today these innovations--function calls, preemptive scheduling, virtual memory--are ubiquitous and invisible and the notion of doing away with them completely or even as default semantics, for all basic programming, would be inconceivable. What small cost they impose upfront by being the default (and often only) construct is vastly outweighed by their power; they're undeniably the correct way to model the vast majority of computing problems at the level with which they're concerned.

I agree, goroutines (or perhaps something a little more generic that doesn't conflate stack reification with scheduling) are absolutely the correct abstraction, and this will be proven in a few decades time. But until then we're stuck with people rationalizing the limitations of async constructs in their favorite languages; constructs primarily chosen because of quirky design constraints, principally C interop and C-based VM implementations that leak the semantics of the C ABI stack.

Java is going a similar route (project Loom), but they'll be implemented in a better way. Things like timeouts in golang are awkard to enforce, and monitoring hierarchies are not built-in. Java's Loom is already getting both.
Getting getting getting, every time I head about how Golang is spanking other languages I see the "BUT MUH JAVA IS GETTING X IN Y $MONTHS".

If you really can predict the future please tell me lotto numbers rather than being abrasive.

The irony is that golang was created to replace C++ at Google, yet it didn't even make a dent in its usage for serious products. C++ and Java remain the heavy lifters there, as well as at other major establishments, precisely because of reasons like performance and (on the JVM) monitoring. golang ended up being more of a Python replacement.
Go was never intended to replace C++. It was aimed at a very specific target: engineers, especially junior engineers, writing function-as-a-service software. Thread-based concurrency (as in logical thread of execution, not "kernel threads") with message-based synchronization, structural typing, and static compilation were their answers to what in their experience were the biggest impediments to writing good network software that could scale reasonably well using the most natural programming approach.

All of the original creators were clearly of the "best tool for the job, even if you have to build it from scratch" persuasion. How many different languages and programming constructs can you find on Unix or Plan 9? The notion of centralizing all development around a single all-purpose language, a la C++ or Java, is anathema to their stated engineering principles and the opposite of the design elements of the many computing environments they spent their careers designing and using.

One can quite easily disagree with their design choices and tradeoffs. I find static compilation short-sighted. But I do appreciate how it fits into their overall approach; and in that way I find static compilation less short-sighted in Go than in Rust. Some aspects of goroutines are problematic. Hassles with dealing with timeouts exposed flaws in their scheduling and message passing abstractions. But those flaws are in the details, not the fundamental model; and the better way to implement those details is more difficult to determine. (I've had to wrestle with such questions myself as I've written multiple async I/O libraries and frameworks. If Go had come out 10 years earlier my entire career trajectory may have been different.)

FWIW, I don't write any Go software. I admire it from a distance, the same way I admire C++, Rust, and Java[1], while I slave away in C and several other languages. Though, there's an honesty and clarity in Go that is lacking in other languages, precisely because Go isn't trying to be an all-purpose language, and because the authors have an understanding of (and deliberately leverage) the interplay between design goals and implementation constraints that can only come with having designed and implemented umpteen different languages before.

[1] I did have a short tryst with Java a long time ago, but it actually ended up driving me into the arms of C. Not because of the language, but because of the ecosystem--licensing, tooling, interop, etc, was an extremely poor fit for Linux, and in many ways still is.

> Go was never intended to replace C++

As per the creators of the language who claimed that they got the idea of writing a new language while waiting for C++ to compile, it was. You can read up about this from them, they were quite clear about it. They even expressed surprise as to why they didn't get the migration of C++ programmers they were anticipating to golang, but instead got Python programmers.

It's not like the lack of green threads stopped people from writing highly concurrent code. Libraries like Vertx, Reactivex, and Akka have existed for a while now. Also, all major platforms have a notion of green threads/coroutines (Java is getting the former and C++ is getting the latter). This was practically the only thing golang had going for it, and once they're implemented for those platforms, it's hard to make a case for golang given it's bad design decisions.

> Hassles with dealing with timeouts exposed flaws in their scheduling and message passing abstractions.

That's a good point, which is why Java's green thread implementation is superior to golang's. Timeouts and cancellations are designed in from the start, as well as hierarchies of green threads (similar to Erlang's).

Again, it just show's that golang does the minimum, and pushes complexity onto the user under the guise of simple language design.

> licensing, tooling, interop, etc, was an extremely poor fit for Linux, and in many ways still is.

The JVM is open source and has been for a while now. Could you elaborate on why it's not a good fit for Linux?

I'm not sure I understand the irony but keen to know what monitoring you are talking about?