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

C doesn't allow you specify what goes on the stack or heap, either. The "stack" in C is called automatic memory. What differentiates automatic memory is that it's automatically released when it falls out of scope. But it can very well be allocated using the same machinery as malloc. Yes, it behaves in some sense like a logical stack, but it needn't reside in some sequentially allocated storage, and the order of allocation or deallocation of objects in the same scope is completely undefined. Indeed, clang supports a mode with two "stacks", so that buffer overflows of automatic array variables can't easily overwrite function invocation bookkeeping.

Go is a fully GCd language with lexical closures. All memory is automatically released when it's no longer _referenced_. So the distinction is irrelevant.

As for volatile, it doesn't really do what most people think it does. volatile prevents _logical_ loads and stores from being moved. What that means for when you're dipping into assembly can vary from compiler to compiler. For typical code the volatile qualifier is only relevant when using setjmp/longjmp, for signal handlers, and in the C11 standard, for some kinds of threading.

In design and spirit I think Go is very much the successor to C. Though, I've never written a line of Go in my life and code primarily in C most days, so I'm only half informed. But if you look at the history of both C and Unix, they were never about performance, per se. What distinguishes them is ease of implementation, ease of portability, and a philosophy of achieving _easy_ performance gains by shifting a subset of hard problems onto the caller (the so-called "Worse is Better" theory). Thus, C was designed so that it could be compiled in a single pass (without an AST). Similarly, one of the reasons the Go compiler is so fast is because of very intentional language design decisions. Those approaches result in all manner of unintended consequences in addition to the intended consequences, and it's important not to conflate the two.



I don't think you can conflate intent with real world application. Certainly they didn't intend for Javascript to take over the server-side world when they built the language.

I don't think you can compare a GC memory model with heap/stack. There's a sliding scale of tradeoffs that you get from a fixed stack -> heap -> GC. There's also a set of hardware out there that doesn't have a unified memory model. There's millions of these types of devices out there in your set-top box, game console and many other places. If you don't have direct control over memory you'll never be able to work with them and will always need a C/C++/Rust wrapper around the low level bits.

Lastly, I'd never want to use volatile for threading[1]. There's no memory barrier semantics, instruction ordering semantics(aside from with other volatile reads). If you need thread synchronization you should to use the platform specific atomics otherwise you're in for a world of pain(and god help you if you're going from x86-win32 -> ARM, there's an implicit memory barrier in x86-win32 that most people don't know about).

[1] Note that volatile variables are not suitable for communication between threads; they do not offer atomicity, synchronization, or memory ordering. A read from a volatile variable that is modified by another thread without synchronization or concurrent modification from two unsynchronized threads is undefined behavior due to a data race. - http://en.cppreference.com/w/c/language/volatile


volatile doesn't offer atomicity, but sig_atomic_t does. You can use sig_atomic_t between threads, but in most cases you need the volatile qualifier as a kind of memory barrier. The guarantees that "volatile sig_atomic_t" provide are very weak and not something you'd normally depend on (especially when you have access to POSIX, C11, or other native atomics), but can be useful on occasion.

I've used it a few times when a library needs to initialize some [very simple] global state, but where I didn't want to require the application to always link in libpthread. Even on Linux that can be an issue for dlopen'd modules. glibc has bugs when late binding libpthread, and some BSDs don't even pretend it works (it just fails loading outright).


> In design and spirit I think Go is very much the successor to C.

It was supposed to, but quickly after release they "pivoted" (is the correct usage of the term?) by rephrasing a bit what "systems" are in "systems languages". I don't quite believe that out of all people, Rob Pike, didn't know what "systems languages", but anyway, it was meant to be replace C, C++ I think, but ended up attracting more of a Python, Ruby and some Java crowd. A lot of Java people I know who ended up using it, had mixed feelings, mostly due to lack of generics (sorry that is a belabored point and mentioning it will probably leads to banning from go language forums at this point). A lot of Python people I know enjoy Go, mostly to do better perceived performance and also ease of deployment.




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

Search: