Lately I've been spending time studying lower-level stuff.
It's interesting that you can tend to think at the level at which you are programming or studying.
When I was studying functional programming I was thinking in high-level terms of elegance; building small pieces of independent functionality that compose together to attack masses of data. Beautiful. That's really programming.
In low-level programming I think "How does this work?". For me low-level programming is really about how things work.
Recently I was doing some string manipulation in a higher language and I was wondering what I was really doing. How this string manipulation was really being done.
Have you ever written code and really wondered what it was really doing? You know and understand what it is doing at the level of the programming language, but what is really happening? Why, how? Is this really inefficient, does it matter? And efficiency aside, just in general interest, what is happening?
Ah yes, premature optimization is the root of all evil. Maybe learning assembly language is the greatest premature optimization. If so I'm guilty. That's like optimizing programs you don't even know about yet because when you write them you'll understand how to write them in a way that is efficient. Maybe so... It seems like it. Speculation, speculation. What do you think?
But for me, even though optimization is so nice and juicy, learning low-level, learning assembly, and even C, speed and optimization is secondary. I want to know what is really happening.
Why do I want to know what is really happening? It's the same reason I'm a programmer. Software is really neat and I want to know how it works and do it. Why are you a programmer?
I have a great book on C. It is called C Primer Plus. It explains C programming in great detail, in an easy and clear way. I feel like I'm learning C without having to program in it.
My biggest problem with C is that it is portable. C aims to be portable. That means there's these abstractions that hide details of what is going on. So off to assembly I go.
One of my high interests in software and programming and one of my goals is to understand the point where hardware turns into software. Right now, I'd say it is that point where a hardware designer designs an interface between his hardware and software programmers. From what I've been learning, I'd say this point is around the CPU, knowing the instruction set of a CPU and using it.
It's interesting that when you are writing software, you are writing it for an interpreter or a compiler. I've just started to get into assembly but it is apparent to me that you are really writing your code for a CPU, for hardware, and you're thinking of your hardware, and not so much your compiler or an interpreter.
I'd really like to write great high-level software, like functional programming, but write it for the hardware, via a compiler/interpreter. To know the compiler/interpreter so well that when I write my code I know what the compiler/interpreter will do with it, and in turn know what the hardware does with the results of the compiler/interpeter. I also know I don't want to be portable. What must one do to know one's compiler/interpeter and hardware so intimately to do this? Write one's own compiler/interpreter in assembly and C ?
19 October 2007
Well, I think what you are describing are simply two different approaches or use cases of programming languages:
The one you're after is about the technical part of it. Why does this work, what are all those registers, how to instruct my CPU to do something and where the heck are all my bits? Using something like assembler or at least C is a /must/ here, I think. If it wouldn't be against the lazy nature of programmers (yes, I actually clicked your link! ;)), you would perhaps fiddle with those bits manually but that's not as efficient and interesting as the real machines.
But there is also the other category, the one that's kind of buggering you. This is where you are likely to prefer high level languages, taking all the nasty work of you. Here, you aren't interestend in RAM access, interrupt vectors and system calls but rather focus on some actual problem. Technical details are totally out of relevance. If your program runs on a quantum processor, a PlayStation or a Windows server setup -- you just don't care. If your object is allocated on a RAM stick, the hard disk or a sheet of paper -- who cares? You rather abolish all traces of the underlying hardware, abstract it away.
I think both approaches are completely valid ways to use programming languages. It's like saying "I'm interested in arts" but nobody would know if you're interested in painting actual images or exploring how brushes work best or even how all those colors are created (all this nasty physics stuff, one further level below).
Just interested, how do you explore assembler? I felt some desire to dive into this topic a few moons ago, too, but couldn't find any particulary good reference (what buggered me off as well is, ironically, the missing abstraction. There were all those different flavors of assembler syntax and different instruction sets for Windows and Linux (syscalls) causing me to run away in horror ;)).
19 October 2007
Write a compiler. You don't need to write it in assembly or C. The important thing is the logic of the transformations. (You can write the compiler for your favorite high-level language _in_ your favorite high-level language, if you like.)
19 October 2007
> Just interested, how do you explore assembler?
Pick a compiler, say gcc. Use gcc -S to make gcc spit out an assembly language listing into a .s file instead of compiling an object file instead of an executable. Now assemble the .s file using gas. You now have a working assembly language program you can start tweaking. Modify the C code and look at the change to the assembly language. It's best to work with optimisation switched off so you get a roughly 1-1 mapping between the C code and the assembly language output.