4 ms·
I don't think that's a misunderstanding at all. The argument is all about control flow and programmer understanding. The actual underlying mechanisms aren't wha
by tomtheelder 9y ago
I don't think that's a misunderstanding at all. The argument is all about control flow and programmer understanding. The actual underlying mechanisms aren't what he is arguing against, instead he dislikes the potential for programmer confusion when code is being executed that wasn't expected. That is 100% possible with goroutines.
Method calls aren't really branching. The code path is still totally linear. You could basically copy paste the code in the method definition in place of its call and get the same outcome (not literally but you know what I mean). For goroutines this is not the case.
I think your points about state ownership are right on, but that's kind of the author's whole point. Right now, there are a lot of things you have to be very conscious of to write good code that executes cleanly using goroutines/threads/etc. That is very much the same as writing good code with gotos. It's 100%, unequivocally possible to write good code using gotos (every control flow structure dijkstra proposed can be represented with them), it just requires a lot of added thought, and the potential for mistakes is much higher.
The author is not proposing any functionality that doesn't already exist, just a new control pattern to reduce the chance of creating problems.
- arghwhat 9y ago> That is 100% possible with goroutines. It really isn't. The big difference is that "goto" can lead to code you read being grossly misunderstood due to complicated flows, potentially even absurd things like jumping to a different function. (And as you mention, good code can be written with goto's—it can make particularly error handlers much easier to read in C.) This is not the case at all with "go", which is extremely clear as to what it does and how the flow will go. However, as a caller, you do not know the flow of the function you call unless you read it. As with any type of asynchronous programming, a function might have scheduled something for later execution: It might be a future, a promise, a timeout/interval, network receive callbacks, or a goroutine. That is, strictly speaking, none of your concern as long as the function lives up to its contract. If not, all bets are off regardless. > ... it just requires a lot of added thought, and the potential for mistakes is much higher. I get your point, but I must disagree that asynchronous programming (which is what goroutines is merely an implementation of) increase the complexity of writing good code, nor increase the likelyhood of state ownership mismanagement in any measurable fashion. > The author is not proposing any functionality that doesn't already exist, just a new control pattern to reduce the chance of creating problems. I don't really find that the author suggests anything new at all. Rather, the author takes an existing blob of code and claims a new benefit from it. EDIT: erroneous "in which case" replaced with "if not", as initially intended.
- wpietri 9y ago> I must disagree that asynchronous programming increase the complexity of writing good code Could you say more about why? It seems to me that purely synchronous code is much easier to reason about than async code, in that a) less is happening at once, and b) things happen linearly. That seems less complex almost by definition. I'd certainly believe that things like goroutines are better than the threading that came before, with way less cognitive load. But I can't see how it's less complex than linear code.
- arghwhat 9y ago> But I can't see how it's less complex than linear code. I am being misinterpreted here (in a peculiar way that has happened before on HN...). I wrote that it does not increase the complexity "in any measurable fashion". It seems that you interpreted this as "concurrency is less complex than non-concurrency", when in reality I am saying "concurrency is a tiny bit more complex than non-concurrency" (extra emphasis on "tiny"). Now, back to the topic: Asynchronous programming is strictly speaking the simple idea that code will be run later when some conditions are met. For example, running a callback when a network response is received from the "fetch" API in modern JS, with all I/O handled behind the scenes by an event engine of sorts. I do not believe that this concept provides any measurable increase in cognitive load. You only concern yourself with these devices where they are used, and they are extremely simple to wrap your head around. In another model, you may have full parallelism and shared memory access, in which case you need to be more careful to only use thread safe structures. Even then, unless you do something stupid™, everything is fine, and the cognitive load is increased globally but only mildly so with a model similar to goroutines and channels. Finally, you may have to design and use synchronized/atomic data structures, in which case things increase in difficulty. While this does increase cognitive load in a small area of the code, I does not increase the cognitive load over the entire application. However, just like not all application need to design a cryptographic protocol, not all applications need to design concurrent data structures even if it uses concurrency. Thus, one should additionally note that this localized overhead is not a universal overhead of all concurrent programming. BTW, I do not find that goroutines present less cognitive load than pthreads ("threading") and a CSP library. They simply present syntactic sugar for a better developer experience. They also give an M:N threading implementation unlike pthreads, but that's an implementation detail.