News for hackers. Stuff that matters.
Re:The descent to C by rayiner on Monday January 27, 2014 @09:58PM (#7135028)
The article is good, but I disagree with this part:

"To a large extent, the answer is: C is that way because reality is that way. C is a low-level language, which means that the way things are done in C is very similar to the way they're done by the computer itself. If you were writing machine code, you'd find that most of the discussion above was just as true as it is in C: strings really are very difficult to handle efficiently (and high-level languages only hide that difficulty, they don't remove it), pointer dereferences are always prone to that kind of problem if you don't either code defensively or avoid making any mistakes, and so on."

Not really, and not quite. A lot of the complexity of C when it comes to handling strings and pointers is the result of not having garbage collection. But it does have malloc()/free(), and that's not really any more fundamental or closer to the machine than a garbage collector. A simple garbage collector isn't really any more complicated than a simple manual heap implementation.

And C's computational model is a vast simplification of "reality." "Reality" is a machine that can do 3-4 instructions and 1-2 loads per clock cycle, with a hierarchical memory structure that has several levels with different sizes and performance characteristics, that can handle requests out of order and uses elaborate protocols for cache coherence on multiprocessor machines. C presents a simple "big array of bytes" memory model that totally abstracts all that complexity. And machines go to great lengths to maintain that fiction.

Re:The descent to C by chubot on Monday January 27, 2014 @11:37PM (#7135343)
And C's computational model is a vast simplification of "reality." "Reality" is a machine that can do 3-4 instructions and 1-2 loads per clock cycle, with a hierarchical memory structure that has several levels with different sizes and performance characteristics, that can handle requests out of order and uses elaborate protocols for cache coherence on multiprocessor machines. C presents a simple "big array of bytes" memory model that totally abstracts all that complexity. And machines go to great lengths to maintain that fiction.

When C was invented, it was very close to reality. It isn't anymore, as you point out. (But as another commenter said, assembly language isn't that close to reality either)

Unfortunately hardware guys and software guys didn't really coordinate, and we just hacked shit up on either side of the instruction set interface.

It is kind of ironic that we write stuff mostly in "serial" languages. But the compiler turns into a parallelizable data flow graph. Then that's compiled back to a serial ISA. And then the CPU goes and tries to execute it in parallel.

It would be a lot nicer if we wrote stuff in parallel/dataflow languages, and the CPU could understand that! Some dilletantism with FPGAs made me realize how mismatched CPUs are for a lot of modern problems.

It's kind of like the idea that Java throws away its type information when compiling to byte code, and then the JIT reconstructs the types at runtime. We have these encrusted representations that cause so much complexity in the stack. C is (relatively) great, but it's also unfortunately one of these things.

Re:The descent to C by pjc50 on Tuesday January 28, 2014 @04:54AM (#7136268)
People have serious problems learning how to write dataflow languages. Itanium exposed its complexity, and was a commercial failure. Similar complaints have been made about the Playstations that made heavy use of explicit parallelism.

It's interesting that you mention Java; some ARM systems have 'Jazelle', a system for directly executing Java bytecode. I don't know how widely used it is.

Re:The descent to C by chubot on Tuesday January 28, 2014 @12:29PM (#7138360)
Good point about Itanium, but that doesn't mean people have problems writing dataflow languages. It's more about the compilers, because very little of the code we run is written in assembly language. Any new architecture will have to gain adoption by having a C compiler.

There were high level dataflow programming languages, like Lucid: http://en.wikipedia.org/wiki/Lucid_(programming_language)

And there were academic dataflow computers as well.

I think D 2.0 makes everything immutable by default (single assignment), so it is close to a dataflow language. And that's no surprise, because Walter Bright designed it specifically to make writing a compiler as natural as possible, rather than having to make complicated inferences about serial code.

My point was that we can never make the jump because the stack of hacks we currently have works "good enough" and it is backward compatible. Generally technologies evolve by accretion, and I'm hard pressed to find an example of radical simplification.

I guess power concerns would be the only hope for something simpler.

It's kind if funny that Backus wondered, "Can programming ever be liberated from the von Neumann model?" This question also applies to hardware too.

Re:The descent to C by lmm on Tuesday January 28, 2014 @05:48AM (#7136376)
Jazelle is now widely recognized as a mistake and has been removed from newer ARMs, AIUI.
Re:The descent to C by mrtbld on Tuesday January 28, 2014 @06:02AM (#7136406)
> Java throws away its type information when compiling to byte code, and then the JIT reconstructs the types at runtime

Is it a fictive analogy or is it actually how the Java VM behaves?

Re:The descent to C by snuxoll on Tuesday January 28, 2014 @12:01PM (#7138173)
That's precisely how the JVM behave, which aggravates a lot of people when writing code using generics. In C# I can do the following:

    public T getInstance<T>() {
        return this.Instances[typeof(T)];
    }
Or, even better:

    public T createInstance<T>() {
        return new T();
    }
Meanwhile Java requires this:

    public <T> T getInstance(Class<T> cls) {
        return this.instances[cls];
    }
The type information above (the generic parameter T) is stripped after compilation, so the Class parameter is needed on the method to get a solid reference to the type we need to work with at run-time. This gets worse when we want to do the second example.

    public <T> T createInstance(Class<T> cls) {
        return cls.newInstance();
    }
It gets even more fun when you throw in non-default constructors. Non-reified generics are a giant pain in the butt.
Re:The descent to C by pkolaczk on Tuesday January 28, 2014 @02:00PM (#7138967)
There are cases when reified generics are a giant pain in the butt and non-reified ones are the right solution. See Scala or F# and .NET interoperability.
Re:The descent to C by chubot on Tuesday January 28, 2014 @12:35PM (#7138405)
It's definitely the case for generics, as someone pointed out.

If you look at the JVM byte code, you can see this has to be the case: http://en.wikipedia.org/wiki/Java_bytecode

Once you're in byte code, you don't have your static types anymore -- that is, types that are independent of control flow. You have types on individual instructions.

So basically you lost some type information before the JIT even sees it. Now, it doesn't actually matter for speed, as Mike Pall (LuaJIT author) would say. His point is that dynamically typed languages can be just as fast as statically typed languages, because you have more information at runtime.

Re:The descent to C by pkolaczk on Tuesday January 28, 2014 @07:56AM (#7136759)
I guess he meant JavaScript. JavaScript is dynamic and JS JITs try to reconstruct types at runtime to improve performance. Java is statically typed and, with a minor exception of generic type arguments, types are accessible both at compiletime and runtime.
Re:The descent to C by saurik on Monday January 27, 2014 @10:20PM (#7135108)
C doesn't really have malloc or free: those are part of the standard library. You can happily code in C without malloc/free, or you can add a library that provides a garbage collected malloc. What C's type system is providing really is bare metal (although as you say, to the abstraction provided by the machine, not to physical reality) to a much more fundamental extent than even a heap allocator, and certainly claiming you could just swap in garbage collection and then have a string type is totally missing the point.
Re:The descent to C by snicklepuff on Monday January 27, 2014 @10:44PM (#7135182)
> C presents a simple "big array of bytes" memory model that totally abstracts all that complexity.

I don't understand what you mean by this. Machine code itself abstracts away the underlying hierarchical memory structure. Sure, some machine language might have instructions to manipulate the cache, but those are easily invoked from C, using either inline assembly or __builtin functions.

Re:The descent to C by agumonkey on Monday January 27, 2014 @10:17PM (#7135093)
I wonder if someone will (or already has) design a low-level language which is async and cache-hierarchy aware.
Re:The descent to C by chubot on Tuesday January 28, 2014 @12:43AM (#7135562)
I stumbled across this paper describing a language that aims to do that. For some reason I was not that excited by the matrix multiplication use case, mainly because that is not the kind of application I'm interested in. I'd like to see examples of stuff a lot of cycles are burnt on in "web" data centers.

But I would like to see more work along these lines -- pointers appreciated.

http://sequoia.stanford.edu/

http://scholar.google.com/scholar?cluster=170564211168157303...

Re:The descent to C by pjmlp on Tuesday January 28, 2014 @01:55AM (#7135758)
Modula-2 back in 1978.

Async is provided via co-routines and is as cache friendly as C.

Re:The descent to C by L8D on Monday January 27, 2014 @10:48PM (#7135196)
That would break the point of it being 'low-level' unless you're saying the standard library and kernel were both designed to function like that.
Re:The descent to C by agumonkey on Tuesday January 28, 2014 @04:57AM (#7136276)
Low level doesn't mean dumb, but giving means to express things about the hardware.
Re:The descent to C by gaius on Tuesday January 28, 2014 @05:05AM (#7136292)
Agreed; a language like Forth is much closer to the machine, tho' if you really want "the machine" then assembly is the way to go, and writing with a good macro assembler is surprisingly high level. I still pine for the days of Devpac.
Re:The descent to C by Dewie on Tuesday January 28, 2014 @02:29AM (#7135867)
> "To a large extent, the answer is: C is that way because reality is that way.

I thought C was so widespread that it eventually started to affect how some computer architectures were designed? If so it seems a bit disingenuous to say that it is only dealing with the reality that it was given.

Re:The descent to C by joelangeway on Wednesday January 29, 2014 @11:01AM (#7144619)
The original machine that influenced C's model of computers was the PDP-11 (http://en.wikipedia.org/wiki/PDP-11). It had a mov instruction instead of load/store. It had no dedicated IO instructions. It could be treated as a sort of generic random access machine (http://en.wikipedia.org/wiki/Random-access_machine) and that is what C did and still does. So there was a reality that C simply modeled, and it was copied (with all sorts of modifications) many times.