Live data from Hacker News

Channels Are Not Enough

gist.github.com

1–10 of 224 posts

Re: Channels Are Not Enough

#2
Yeah it seem channels are basic primitives. Kind of a like a class in OO programming.

Just like Erlang has explicit processes and message sending primitives So it is pretty simple and concise at that level. In order to build large systems there is OTP (or e2) that embodies and abstracts away some common patterns/behaviours: gen_event, gen_server, gen_fsm, supervisors, logging, distribution between nodes etc.

I imagine over time go will acquire those kind of libraries (maybe it already has them?).

There is also an interesting duality between Erlang and Go. In one case there are explicit processes (identified by PIDs) + an anonymous (implicit) mailbox. Where go has anonymous goroutines but explicitly identifiably channels. It seems they are duals. You can simulate one with another. And you can build concurrency patterns on top of them.

I personally prefer Erlang's model to think about concurrency. There is an active entity -- a client request, a server, a socket handler, it has a an id/name, it can be monitored for liveliness, it can be halted, upgraded, killed, can send messages to it. Somehow to me that makes it easier to map to concurrent problem domains. Channels can ultimately do the same things but it is harder for me to design using goroutines.

Re: Channels Are Not Enough

#3
post #2

Yeah it seem channels are basic primitives. Kind of a like a class in OO programming. Just like Erlang has explicit processes and message sending primitives So it is pretty simple and concise at that level. In order to build large systems there is OTP (or e2) that embodies and abstracts away some common patterns/behaviours: gen_event, gen_server, gen_fsm, supervisors, logging, distribution between nodes etc. I imagin…

The problem (which the article touches on) is that you have to resort to interface{} to make things reusable since Go doesn't have generics. So you have to pick between using a library (which will handle edge cases better) or compile time type checking.

Re: Channels Are Not Enough

#4
This is a really great read, and goes beyond just channels and concurrency. It seems to me that Go is designed to discourage developing higher-level abstractions. That was my sense using it in the past, and it's only gotten stronger over time.

Remember that one of Go's primary stated goals is "speed of compilation"[1]. Simplicity and ease of learning are paramount, and it's easier to learn a language where any chunk of code basically follows the same rules as any other.

[1]: http://golang.org/doc/faq#Why_doesnt_Go_have_feature_X

Re: Channels Are Not Enough

#5
post #3
post #2

Yeah it seem channels are basic primitives. Kind of a like a class in OO programming. Just like Erlang has explicit processes and message sending primitives So it is pretty simple and concise at that level. In order to build large systems there is OTP (or e2) that embodies and abstracts away some common patterns/behaviours: gen_event, gen_server, gen_fsm, supervisors, logging, distribution between nodes etc. I imagin…

The problem (which the article touches on) is that you have to resort to interface{} to make things reusable since Go doesn't have generics. So you have to pick between using a library (which will handle edge cases better) or compile time type checking.

How about replacing certain compile time type checks with smoke tests and runtime assertions, or unit tests?

Re: Channels Are Not Enough

#6
It's funny that OP uses Twitter as the case study at the end. I wrote what was then the first (and think still the only) Go Twitter client library that works with v1.1 of Twitter's API[0]. It implements automatic rate-limiting/throttling behind the scenes, and it returns values of concrete types (not interfaces) ready for immediate use.

Keep in mind that, were I to write this again today from scratch, there are a number of things I would do differently (since I started it as a relative beginner expanded on it as my familiarity with Go developed, it's grown to be a bit over-engineered in places). But I still think it's a worthwhile example in this discussion.

For concurrency, I wouldn't say that what OP is trying to do is going to be easy in any language, because OAuth in general kind of sucks[1] the Twitter API itself has a number of quirks that make it cumbersome in general, irrespective of language[2]. That said, Go was by far the easiest to work with here, because channels allowed me to abstract the pagination and the rate-limiting in a way that it would be invisible to all callers, but "magically" handled behind the scenes.

Without going into too much detail, I can see that the way OP has designed his code looks a bit cumbersome. That said, while it's a reasonable way of approaching it, I don't think it's actually the best approach in Go given the language's idioms.

One other thing I want to draw attention to is the use of the general-purpose function for issuing a GET request to Twitter, and how that is shared among the various functions that use it to return values of varying, but known, types.

I don't want to use the word "generic" here because people expect a certain thing when they hear that word, but I will say that this function is (A) general-purpose, and (B) type-safe - it involves no type assertions, and the functions all return concrete types instead if interface{}.

[0] https://github.com/ChimeraCoder/anaconda/

[1] Don't get me started on this

[2] I've written client libraries for Twitter in a few different languages, so I actually have a reasonable point of reference on this - at one point, it was my personal "hello world" for testing out a new language.

Re: Channels Are Not Enough

#7
Wouldn't a library like zeromq address the complications/shortcomings the OP highlights in his article, when working with Go channels on a regular basis? Using the 'inproc' for message transport with zeromq should give similar performance to pure go channels no?

This Go client implementation https://github.com/pebbe/zmq4 by Peter Kleiweg also includes all the examples from the online zeromq guide which is great.

I know it's not a pure ago solution but the OP does mention that

'99% of time I don't really care if the response is delivered with a channel or a magical unicorn brought it on its horn.'

I don't know, maybe I'm missing the point of the article.

Re: Channels Are Not Enough

#8
post #3

Earlier quoted context omitted.

The problem (which the article touches on) is that you have to resort to interface{} to make things reusable since Go doesn't have generics. So you have to pick between using a library (which will handle edge cases better) or compile time type checking.

How about replacing certain compile time type checks with smoke tests and runtime assertions, or unit tests?

Why do what the compiler can do for me?

Re: Channels Are Not Enough

#9

Wouldn't a library like zeromq address the complications/shortcomings the OP highlights in his article, when working with Go channels on a regular basis? Using the 'inproc' for message transport with zeromq should give similar performance to pure go channels no? This Go client implementation https://github.com/pebbe/zmq4 by Peter Kleiweg also includes all the examples from the online zeromq guide which is great. I kn…

Sure, but at that point what is the point of using Go? You might as well use some other language like D if all the parallelism and message passing patterns are going to be handled by a library like zeromq.

Re: Channels Are Not Enough

#10

It's funny that OP uses Twitter as the case study at the end. I wrote what was then the first (and think still the only) Go Twitter client library that works with v1.1 of Twitter's API[0]. It implements automatic rate-limiting/throttling behind the scenes, and it returns values of concrete types (not interfaces) ready for immediate use. Keep in mind that, were I to write this again today from scratch, there are a num…

I'm curious to see this general purpose function of yours. You are also addressing a different point than the article. The main point is that patterns like parallel map are impossible to implement in Go in a type-safe manner. This is a valid complaint depending on what is meant by type-safe and at this point the arguments for/against Go usually devolve into name calling and matters of culture. If you could factor out all that general purpose functionality from your code base, e.g. the rate-limiting and other things, and turn it into a re-usable library then that would be an entirely different matter. Whether that would qualify according to the author's definition of type-safe is another matter.
Post reply on HN