3 ms·
> but that doesn't mean there isn't merit in it Of course not. It also isn't original, or a "silver bullet" that I find relevant to general concurrent programm
by arghwhat 9y ago
> but that doesn't mean there isn't merit in it
Of course not. It also isn't original, or a "silver bullet" that I find relevant to general concurrent programming.
> I don't really understand what you mean by this.
I was trying to keep my rant a bit short, but my point is that the only practical example for a post that puts a lot of effort into complaining about a core Go construct (it's the title) does not even remotely apply to Go.
This is partly due to Go being shaped around this very core construct.
> Why exactly is branching better?
"goto" can (sometimes, as there are many valid usecases) be problematic as it can make control flow very obscure when read. "go" is extremely clear to read, and only has the concern that you don't know if a given function has created goroutines. It is of course usually described by documentation, or implicit from functionality that such thing will occur, and unlike goto, the code is extremely clear about what is going on if you read it.
Furthermore, whether a function call has created goroutines is by itself not a concern. What can be a concern would be if some types of resources that must be closed (i.e. a file) is referenced after you close it. That is not related to concurrency, but lifetimes.
By lifetimes, I do not necessarily mean Rust-style compiler-enforced lifetimes (which I like), but simply API contracts. A library may store a reference to something you pass, and may use this reference in later calls, potentially after you invalidated the reference by closing a file descriptor.
A joined execution does not even remotely solve this problem, as it is not related to concurrency. It solves a different problem, related to just managing concurrent execution.
> These are all related concepts. They are about doing different things "at the same time, ...
They are not at all. Callbacks are often used together with certain types of concurrency constructs, such as an event-loop that can call callbacks upon various events. In JS, for example, the concurrency construct is a single global event-loop that calls tasks/microtasks.
Callbacks themselves, however, are not a concurrency construct. Thus, comparing them to concurrency constructs is very weird.
(A SAX parser is an example of a non-concurrent use of callbacks.)
> Even using threading with a GIL can create execution paths that you aren't really aware of until you actually look through the code or debug.
It does not create execution paths that are not easily visible (you know nothing about a program until you look through the code), but yes, threading.Thread can lead to some unanticipated behavior.
Note that I was excluding this as a parallelism construct, not a concurrency construct. The behavior will be some form of cooperative multi-tasking.
EDIT: too much "however".
- tomtheelder 9y agoAh I get what you mean about the use of go as an example. Also, I think when the author refers to callbacks they are referring to callbacks in the JS sense, that is to say callbacks in the context of an event loop type environment. The author certainly wouldn't care about other types of callbacks, since they do not create the split execution paths that he is describing. The distinction you are trying to draw between concurrency and parallelism, while totally valid, isn't particularly relevant here. The problems the author is describing are almost entirely to do with developers writing and understanding code, and they generally apply to both parallel and concurrent systems. The user experience of writing parallel and concurrent code can often feel extremely similar, so the tools the author is describing will tend to apply in both situations.