Hacker News new | ask | show | jobs
by brlewis 3350 days ago
Every higher abstraction could be described as an attempt to pretend that the lower abstraction is less complicated and error-prone than it actually is.
1 comments

I know - I'm being facetious, but really, if you want to really understand how most modern computers actually work, there's probably no better way than to learn C. It's high level enough and provides enough structure so that you don't need to actually blurt out a bunch of assembly instructions, but low-level enough so that your code mostly more or less corresponds to what the underlying Von Neumann hardware is actually doing.
I'm not convinced c without assembly is much better than Pascal or even Rust. Sure, you might not need a full assembly course (write a real, multi-user, bare-metal os in assembler using most of x86 16,32 and 64bit syntax) - but a C course mixed with assembly I think makes a lot of sense if the goal is to learn a bit about how computers get work done.

I mean, one should be able to look at the assembler output of hello.c and have an idea of what's going on. Without that level of understanding, I'm not convinced using C over many other languages gain you much. It's still a lot simpler than eg. c++, though.

I'm thinking something like: http://pacman128.github.io/pcasm/ but rewritten from the ground up for x86_64.

I think it depends on what modern means. If modern means more or less the system architecture basics from the 80s that our current systems pretend to be, C is a pretty straightforward mapping; but if modern means Intel kaby lake/amd ryzen, there's a lot of things going on that C or even assembly don't really address.
if you want to really understand how most modern computers actually work, there's probably no better way than to learn C

I have found advice like this to be a good sign that the speaker has a very limited understanding of how modern computers actually work.

How computers really work never clicked until I took a computer architecture class where we started in a logic simulator with individual gates, and progressed step by step until we had an 8-bit computer, running in the simulator, that could load in machine code generated by an assembler we wrote for that simulated computer, or compiled from a cut-down dialect of C.

That was a long semester.

You take a course in computer architecture to learn how computers work. If you follow up with assembly, you'll be able to do things you can't express in C without breaking its common model. What the underlying hardware is doing also varies considerably across implementations: x86 CISC; RISC's; embedded; SIMD/MIMD; multicore; HLL or safe/secure CPU's; DSP's; GPU's. I know C doesn't map to a lot of that because there were whole Ph.D. programs trying to extend it with things like Cilk language. However, you learn C language if you want to learn its model or how to work on software using it. It will also teach you a little bit of what a computer architecture course will but leave off parts that could help a lot.
Of course C doesn't map to all that. Neither do most of the MIPS emulators they actually use to teach MIPS assembly in universities. But it does map pretty well to basic loops/conditionals and other intro-to-programming stuff.

I mean, just write a simple C program that reads in argv[1] and then loops from 1 to atoi(argv[1]) doing fizzbuzz. Then compile the program (without optimization) and look at the generated assembly. I just did that on an x86_64 using gcc, and the generated assembly is pretty straightforward and maps pretty well to the actual C code.

The only part that doesn't neatly map to the C code is the boilerplate call-stack stuff, (subq instructions on the rsp register, etc.). But everything else maps rather neatly. The library calls to printf, etc. are mapped to a simple call instruction. It demonstrates how closely C code maps to the actual assembly for these sort of simple programs, which is what actually matters in a pedagogical environment.

This compared to similar Python code, where the actual op codes being executed would be vastly more complicated and less obviously related to the actual "business logic" of the program - you'd have constant incref/decref'ing of objects (assuming CPython), byte code execution in the main ceval loop, hash table lookups for globals, etc. etc. The point is C code maps much better to what the hardware is actually doing. Your arguments to the contrary (talking about vectorized instructions and GPU) are really just being nitpicky. That stuff can be covered later in more advanced courses.

Your facetious claim was that understanding how a modern computer works is best done by learning C. I said it's best done by learning how a modern computer works with classes on computer architecture with intros to fundamental techniques. The comment I'm replying to has good detail on ways C maps to computers better than most languages. Original claim is still false across the board where people capitalizing on underlying hardware are better off understanding various forms of computing followed by languages that take most advantage of each or most of them.