4 ms·
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 hie
by chubot 13y ago
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.
- pjc50 13y agoPeople 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.
- lmm 13y agoJazelle is now widely recognized as a mistake and has been removed from newer ARMs, AIUI.
- chubot 13y agoGood 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) 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.
- mrtbld 13y ago> 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?
- pkolaczk 13y agoI 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.
- snuxoll 13y agoThat'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.
- pkolaczk 13y agoThere 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.
- chubot 13y agoIt'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 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.