Live data from Hacker News

Why Go Is Not Good (2014)

yager.io

411–420 of 466 posts

Re: Why Go Is Not Good (2014)

#411
post #409

Earlier quoted context omitted.

Once you get data races in Go, you realize that immutable data structures are indeed the right way. Too bad though. That non-threadsafe, racy map is your only generic data structure. I think that critics are generally cutting way too much slack to Go. Its a horrible language - with a decent library and excellent tooling and documentation, but still quite horrible.

> Once you get data races in Go, you realize that immutable data structures are indeed the right way. False. There are more things in multi-threaded programming than are dreamt of in your philosophy. For some of them, immutability is very much the wrong way. It means some threads will be playing with stale data for some time. I'm not saying that I'd want to write that kind of a program in Go, mind you. But your over-…

Even if we assumed that (but seriously though, I invite you to at least provide one valid, complete example) your argument is valid, what you're saying is that Go is good for that subset of cases ("some of them") where immutability is the wrong way.

Does not invalidate the fact that it has zilch to offer for the cases where its the right way.

Re: Why Go Is Not Good (2014)

#412
post #388

Earlier quoted context omitted.

I agree with most of your "so what?" point, but I think the lodash / FP thing is interesting because javascript is also not trying to be a functional programming language, and nor are the many other languages that have popular higher-order-function libraries (eg. Java, C#, Ruby, Python). There's a long trend of pulling in the ideas from functional languages that have proven to be generally useful, like lodash / Java…

As was mentioned before, you can absolutely do the same thing in Go that you see in lodash by giving up type-safety which javascript doesn't have anyway!.

Or you don't give up type safety. TypeScript compiles really fast and has generics.

Re: Why Go Is Not Good (2014)

#413
post #411

Earlier quoted context omitted.

> Once you get data races in Go, you realize that immutable data structures are indeed the right way. False. There are more things in multi-threaded programming than are dreamt of in your philosophy. For some of them, immutability is very much the wrong way. It means some threads will be playing with stale data for some time. I'm not saying that I'd want to write that kind of a program in Go, mind you. But your over-…

Even if we assumed that (but seriously though, I invite you to at least provide one valid, complete example) your argument is valid, what you're saying is that Go is good for that subset of cases ("some of them") where immutability is the wrong way. Does not invalidate the fact that it has zilch to offer for the cases where its the right way.

First: I didn't say that Go was good for that subset of cases. In fact, I said that I wouldn't want to write that kind of program in Go. I said that Go wasn't the wrong answer for the reason you stated, namely immutable data.

You want an example? Here's a video router for a TV station, which has multiple sources of user input (human-pushable control panels on two different data buses, plus serial data coming from multiple automation systems). You need to keep those control panels and automation systems updated with what's connected to what, even if they weren't the source of the command that changed it. And you need to keep the actual hardware switch up to date, too. And commands to the switch can fail, which you need to report back to whoever made the command. (One way the command can fail is if someone else locked an output to display a particular input.)

Faced with that problem, we implemented a single "state of the switch" data object that mutated as commands came in. But you could think about trying to implement it with immutable data. That would mean creating a new copy of the state of the switch for each (successful) command that was processed. That would mean copying a fairly large chunk of data many times a second, which would have been a challenge for the processor we had. That would also almost certainly mean a garbage-collected language which, when you're trying to respond within one TV frame (1/60th of a second), is a really bad idea. More to the point for our discussion, it would also mean that threads, which in our design only had to respond to one source of control, would now also have to handle state-of-the-switch updates pushed to them from other threads (or from some master). That seems like significant additional complexity to me. (Yes, I know that data races have their own complexity, but for our design, it was very clear how to prevent that. And if you're going to say that we could have had a separate thread receive the updates to update the control panels, now we've got a race as to who owns the hardware control bus to the panels.)

Re: Why Go Is Not Good (2014)

#414

For me personally, it's not what the language offers syntax-wise but what I can do with it. I was excited about Ruby because of Rails; only after working with it did I pick up a book on Ruby itself and come to appreciate the cleverness of block arguments (Ruby's insight, that functions that accept another function as an argument almost always accept at most one, so special-casing the syntax for that to make it clear,…

[deleted]

Re: Why Go Is Not Good (2014)

#415
post #411

Earlier quoted context omitted.

Even if we assumed that (but seriously though, I invite you to at least provide one valid, complete example) your argument is valid, what you're saying is that Go is good for that subset of cases ("some of them") where immutability is the wrong way. Does not invalidate the fact that it has zilch to offer for the cases where its the right way.

First: I didn't say that Go was good for that subset of cases. In fact, I said that I wouldn't want to write that kind of program in Go. I said that Go wasn't the wrong answer for the reason you stated , namely immutable data. You want an example? Here's a video router for a TV station, which has multiple sources of user input (human-pushable control panels on two different data buses, plus serial data coming from mu…

Now thats a good example!

First, a little correction: you don't have to make a copy of the entire state. This video explains the trick on how to get immutable data structures that share most of their data with their previous version https://youtu.be/SiFwRtCnxv4?t=8m39s - list are straightforward, and vectors and maps are based on the same HAMT tree-like structure.

Of course, a system with real time constrains and hardware limitations will have different optimal solutions. And yes, reference counting is the bare minimum you'd probably like for these structures (GC is even better)

However, we're talking about Go here - a language designed for writing servers that has a GC.

The solution in Haskell is actually quite nice: MVars [1] plus immutable data structure. An MVar contains the current state, represented by one such structure. takeMVar "removes" the variable - a thing which can be done atomically by the updating thread when the data becomes stale. After that, subsequent attempts to readMVar from other threads would block until there is a new updated value, to ensure everything is in sync. Finally, the updating thread does a putMVar, and all readers get the new value and continue executing.

The best part is they don't have to worry that the updating thread might start another update in parallel while they read: the data structures are immutable so the value being read is guaranteed to remain immutable. Even if the updating thread continues "modifying" the new structure in the background, it doesn't have an effect on the other consumer's version.

But yeah, all this is pointless if you have realtime constraints and therefore need super-tight control over execution time. It might be doable in a fast reference counted language, but it will also be much harder to reason about the time it will take to release the memory for the segments that aren't in use anymore.

[1]: https://hackage.haskell.org/package/base-4.8.1.0/docs/Contro...

Re: Why Go Is Not Good (2014)

#416
post #415

Earlier quoted context omitted.

First: I didn't say that Go was good for that subset of cases. In fact, I said that I wouldn't want to write that kind of program in Go. I said that Go wasn't the wrong answer for the reason you stated , namely immutable data. You want an example? Here's a video router for a TV station, which has multiple sources of user input (human-pushable control panels on two different data buses, plus serial data coming from mu…

Now thats a good example! First, a little correction: you don't have to make a copy of the entire state. This video explains the trick on how to get immutable data structures that share most of their data with their previous version https://youtu.be/SiFwRtCnxv4?t=8m39s - list are straightforward, and vectors and maps are based on the same HAMT tree-like structure. Of course, a system with real time constrains and har…

> The best part is they don't have to worry that the updating thread might start another update in parallel while they read: the data structures are immutable so the value being read is guaranteed to remain immutable. Even if the updating thread continues "modifying" the new structure in the background, it doesn't have an effect on the other consumer's version.

If I understand what you said here correctly, this doesn't work for my example. A thread cannot continue with a stale version (and function properly). It must operate on a current version all the time (or block until it can).

Re: Why Go Is Not Good (2014)

#417
post #415

Earlier quoted context omitted.

Now thats a good example! First, a little correction: you don't have to make a copy of the entire state. This video explains the trick on how to get immutable data structures that share most of their data with their previous version https://youtu.be/SiFwRtCnxv4?t=8m39s - list are straightforward, and vectors and maps are based on the same HAMT tree-like structure. Of course, a system with real time constrains and har…

> The best part is they don't have to worry that the updating thread might start another update in parallel while they read: the data structures are immutable so the value being read is guaranteed to remain immutable. Even if the updating thread continues "modifying" the new structure in the background, it doesn't have an effect on the other consumer's version. If I understand what you said here correctly, this doesn…

You're right. For your example thats actually an error, and it wont happen if you `takeMVar` before you start working on the new value.

I'm describing a slightly different example there, where its okay to get the old data while updates are being "prepared" (e.g. every item in the dictionary is being fetched from the DB, typical for a server app). In that case, Haskell will work correctly. In Go on the other hand, reusing the data structure may result in a program crash, as Go's built in maps (which might contain that data) are not thread-safe.

(You can't even make the simplest type-safe, thread-safe mutable map that uses a RWMutex automatically under the hood. Because there are no generics)

Re: Why Go Is Not Good (2014)

#419
post #230

Earlier quoted context omitted.

> * Its forced syntax stops syntax wars. Okay, but so does any in-company linter. > * Compiling down to one binary makes deployment easy. Rust and Haskell are both compiled to a single binary, typically, and both can be statically linked (with some work.. this is getting better) > * Its has concurrency out of the box. Rust is actually a systems language and does not have a decent semblance of concurrency (beyond OS t…

> Rust is actually a systems language and does not have a > decent semblance of concurrency I have bias here, but so strongly disagree. Many concurrency errors are at compile time in Rust. Rust has a really, really strong concurrency story.

I meant higher-level concurrency. Threads are great and all, unless you're trying to write a network server.

Last I checked, there were no thread-safe async/await primitives, coroutines, standard event-loops/reactors built into the language or the stdlib, though I would be very happy if this turned out to the case.

To preempt: Mio is not an acceptable answer without multi-threaded reactor capabilities and compiler-supported primitives to make the callback interface pleasant.

I would also state that Mio makes me fear that Rust will suffer the same horrible fate as Python or Ruby in this department: tons of fragmented, incompatible implementations with no blessed one. I really want to use Rust, but this is a deal-breaker.

Re: Why Go Is Not Good (2014)

#420
post #419

Earlier quoted context omitted.

> Rust is actually a systems language and does not have a > decent semblance of concurrency I have bias here, but so strongly disagree. Many concurrency errors are at compile time in Rust. Rust has a really, really strong concurrency story.

I meant higher-level concurrency. Threads are great and all, unless you're trying to write a network server. Last I checked, there were no thread-safe async/await primitives, coroutines, standard event-loops/reactors built into the language or the stdlib, though I would be very happy if this turned out to the case. To preempt: Mio is not an acceptable answer without multi-threaded reactor capabilities and compiler-su…

I think that's conflating non-blocking I/O and threading models a bit, but still, I hear you.

I and other team members were literally in a few hours of meetings over the last few days to talk about this, and how to ensure it won't happen. It will be fine.

Post reply on HN