Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Interesting comparisons.

However (not slating Go, which I think is excellent), I genuinely think Go is going to go the same way as plan9 eventually. Unfortunately, its predecessor (C) is good enough, much as UNIX was good enough compared to plan9.



The devil is in details. Go is great for hi-level or simple stuff like that, but is not really usable for system programming. If things are a bit more complicated, the go runtime stays in the way. For those problems, after a while, the bare metal support was removed from the language completely...


Ever heard of Oberon, Modula-2 and Modula-3?

These languages also had OS fully implemented on them, just with tiny bits of Assembly to do the very low level stuff, similar to what C would require anyway.

The only advantage of C is that its runtime is so small, that in practice the OS is the C's runtime.


It's not the only advantage. Another, more important advantage of C and C++ over Go is a lack of stop-the-world garbage collection (and predictable memory usage under high load).


You can predict the time that malloc(3) and free(3) take to run? You know they are backed by very complex data structures that need to manipulated and iterated over?

The point you mention is only valid when using entirely static memory, which is a very rare case in real C code (only really used in a few small embedded codebases).


>You can predict the time that malloc(3) and free(3) take to run?

The correct answer would be: depends on the concrete implementation. There are implementations with real-time guarantees.

However, assuming standard desktop OS malloc()/free() the answer is: No. These functions can execute very quickly.. or very slowly, depending on their current internal state. But you can control when they get called, which can be an important difference.

>The point you mention is only valid when using entirely static memory, which is a very rare case in real C code (only really used in a few small embedded codebases).

Depends on what you mean by "entirely static memory". No malloc() calls at all? Yes, that is rare and pretty much limited to the embedded realm I think. Memory pools however are very common in performance critical code.


You speak sense. I tend to use apr pools all the time in critical sections.


> You can predict the time that malloc(3) and free(3) take to run?

Thanks for pointing this out.

This is often a misunderstanding from manual memory management fans. In many cases malloc()/free() also behave non-deterministic.

This is the main reason why for special types of applications, you need to have malloc()/free() implementations specially targeted to the use case at hand.

This is no different from the GC runtimes, which are coded specifically for real time applications, like avionics, for example.


It's very different in one significant regard: it's very easy to write your own acceptably performant and deterministic malloc and free, compared to the effort it takes to write a GC that would fit in to those constraints.


malloc and free are much cheaper than a mark-and-sweep. It is a much easier task to write a bounded-latency malloc suitable for real-time applications - for example, dlmalloc has a NO_SEGMENT_TRAVERSAL flag that assures bounded execution. By contrast, making GC with bounded latency is hard.


Why are you comparing an API (malloc/free) to an implementation (mark and sweep)?

Anyway, take a look at the OCaml GC. It's simple (probably simpler than glibc's malloc) and very performant particularly if you understand how it works and use it intelligently in your app.


Not that complex really, if we are talking about buddy allocator or jemalloc. They both have predictable and limited running time.

Default platform malloc(3) and free(3) can be a crap indeed, but they are drop-in replaceable with the above at any time, unlike Go GC - if practical testing suggests such replacement is necessary (e.g. Firefox, Facebook servers)


> The point you mention is only valid when using entirely static memory

Exactly, and you can also do that in Go to avoid the GC.


Not sure exactly what you mean by "entirely static", but in the signal processing application I worked on we used an allocate once/deallocate once design where we allocated gigabytes of RAM per node up-front and reused the buffers and data structures during operation. We took over the entire node, essentially, and we were a closed system, so this design didn't cause most of the problems this normally would.


Aren't they dead? Seriously. If you write programs at OS level, you need the control over memory, timing, etc. In go you have no control about the runtime at all. Don't get me wrong. Go is fantastic for any kind of gooooogle, cron, at, ... server stuff. At OS or bare level you unfortunately need something other than a sledgehammer.


> Aren't they dead?

Yes, but only because no major OS manufacturer picked them up as the main system language.

The only way a system language can become mainstream is if it is picked up by an OS vendor that makes it the default system language on their OS.

As for the bare level stuff you describe, real systems like Native Oberon proved this is possible. At ETHZ Native Oberon was used for almost everything an OS is used for.

Sadly no major vendor has got interested on the system, even after some industry attempts tried out by ETHZ.


> For those problems, after a while, the bare metal support was removed from the language completely...

Not really true, you have direct control over the memory layout of your data structures, and if you want to do really tricky stuff there is also the unsafe package.


I think nux6 means running Go programs without an OS, directly "on the metal". There was a proof of concept early on, but it was abandoned.


Even the pet looks similar hehehe :P


Could be because they were both created by the same person.


The big win for go over c is the goroutines - cheap and easy multithreading built right into the language.


I agree entirely - they are great, but in all the Go I've written (which totals about 50kloc so far as a porting project), I haven't actually used them past anything I would have done with zmq in C.


Goroutines are great, but I'm not convinced they are the greatest advantage over C.

Go cleans up and fixes pretty much every issue C had, and improves it in many non-obvious areas, from the syntax to the type system.

And when porting an existing project I'm not surprised if goroutines would come up that often given that they probably don't have any equivalent in the original design.


zeromq or coroutine libraries like libtask (by a go author!) have greatly reduced this advantage.


libtask looks really cool. Thanks for posting.

I suppose that begs the question: if you can built it in the language, should it really be a part of the implementation?


Plan 9's libthread ( http://man.cat-v.org/plan_9/2/thread ) provides similar CSP-style concurrency to Go. Yet, the authors, after using it for many years, and after having used and built systems where it was part of the language (eg., Inferno/Limbo) decided it was important enough to make it part of the language for it to be usable.

There are also other language features that make it much more usable and that are missing from C, like garbage collection.

I know Rob Pike and Russ Cox have discussed this several times, it might be worth watching this talk by rob about the history of Go's concurrency model you can find here: http://go-lang.cat-v.org/talks/

And Russ Cox's article also about this: http://swtch.com/~rsc/thread/

I'm not sure either covers exactly the reasons why it is a great advantage to make it part of the language, but they are still interesting background.


Thanks for the information - I will have a good read this evening :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: