Why Learning Assembly Language Is Still Good
nickirelan writes "Why Learning Assembly Language Is Still a Good Idea by Randall Hyde -- Randall Hyde makes his case for why learning assembly language is still relevant today. The key, says Randall, is to learn how to efficiently implement an application, and the best implementations are written by those who've mastered assembly language. Randall is the author of Write Great Code (from No Starch Press)."
Another reason: Sooner or later, you'll need to debug something without a source-level debugger. Knowing how to debug raw assembly language has saved my ass many times.
Also, don't forget, a good deal of programming is still done in assembly. Both in a job I've had coding stuff and in my current research (crypto), I did/do a lot of assembly programming. Yes, learning assembly will make a better programmer out of those who never will code assembly again, but for some people, assembly is a valuable and often-used skill
It's a shame that schools are phasing assembly classes out of their computer science curriculums. If anything, it makes for a great foundation on which to learn more modern languages while teaching students things about computers that they probably wouldn't take the time to learn otherwise.
Hate to say, but the kind of optimization you learn about by knowing assembly language is just not necessary for most programmers these days.
I learned programming in the 80's, and I did learn assembly language, starting with 6502 assembly. I would subconciously code my C so that it would produce faster code. Every block of code I wrote would be optimized as much as practical. My code was fast and confusing.
When coding Perl or Java I would keep in mind the details of the underlying virtual machine so I could avoid wasteful string concatenation or whatever. I cache things whenever possible, use temp variables all the time, etc., etc.
I've spent the last few years trying to UNLEARN this useless habit. There is just no need. And in highly dynamic languages like Ruby, it's pointless. You can't predict where the bottlenecks will show up.. almost every project I've worked on has either had no performance problems, or had a couple major performance problems that were solved by profiling and correcting a bad algorithm.
Stuff like XP and agile development have it right: code as simply as possible, don't code for performance, then when you need performance you can drill down and figure out how to do it.
To me a beautiful piece of code is one that is so simple it does exactly what it needs, and nothing more, and it reads like pseudo-code. Minimalism is the name of the game.
So my advice is, don't learn assembly language. Learn Lisp or another abstract language. Think in terms of functions and algorithms, not registers and page faults. Learn to program minimally.
On another note, the tab in my Konqueror for this article reads: "Slashdot | Why Learning Ass...". Heh. :-)
While I learned assembly, and found it useful for learning to understand exactly how the machines think, I'm not sure I agree with his basic premise. Namely, that great code (code that is well designed for it's job, and easy to work with and under) is always the efficient code, in machine terms.
The machine thinks one way. A human thinks in another. Code that is well designed for easy updating, and extending, is code that is easy for a human to understand. If that is not the most efficient way for the machine to do it, that may be the price for 'great' code in this project. (The ideal balance depends on the project, of course. A kernel should be machine-efficient, for example.)
'Sensible' is a curse word.
Efficiency in terms of coding is a wonderful art and I think it's still applicable today. Kernel-level routines, games, drivers, etc. all benefit from tight coding in assembly language.
But let's be honest here. Computer Science 101: an efficient algorithm coded in an inefficient way will always beat out an inefficient algorithm coded by hand in 100% optimized assembly. I'll put my crudely coded Javascript quicksort algorithm against your finely honed 100% assembly bubblesort algorithm any day. Not only will my algorithm beat the pants off of your algorithm, but I'll also code it in far less time and with way fewer debugging sessions than you would. Also, the higher-level language you go, the better it is for security. How easy is it to introduce things like buffer overflows, array out of bounds, etc. errors in assembly? How easy is it to do that in Java, C#, etc.?
So yes, writing in assembly language is still good and has its places. But let's keep it to those places, shall we?
Want to improve your Karma? Instead of "Post Anonymously", try the "Post Humously" option.
Fuck, I'd settle for viruses smaller than 400K! Of all things, you'd expect a virus to be lean and mean, but I guess the latest crops were made with Visual Virus .NET or something to that effect.
I've programmed a few embedded systems in assembly and it's not very fun at all.
To make matters worse, each CPU has it's own instruction set, and special set of commands that you must learn before you can even sit down and start writing code.
With C++ or at least a C compiler, you don't need to worry about so many implementation details. You should only resort to assembly if you absolutely, must have the performance required. Maybe the author of this article forgets how difficult it is to debug assembly code, or how difficult it is to implement abstract concepts such as OO at such a low level.
I don't agree at all that writing "efficient code" necessarily creates better code. Writing "clearer" is better from a quality standard.
We have compilers for a reason, to produce assembly code as efficiently as possible for a higher level language. Most 99% of the time, the compiler will optomize the code just as well, or better than you can.
I would still recommend learning assembly language to C++ programmers simply so they understand how the computer is actually working. But to require anyone to program in assembly requires a great deal of justification.
can you get away with naming a source file org.asm?
* rim shot
I apologize.
Wow. You can crash a machine with assembly language.
That may seem impressive to you (especially if you're fourteen), but the fact is that exploits can be done in almost any language.
In other news, this doesn't have a hell of a lot to do with the posted article, either.
Assembly language will always be needed to optimize certain types of algorithms, that don't translate efficiently into C. Try writing a FFT algorithm on C using a DSP, and compare it to what can be done in native assembly. The difference can be an order of magnitude or more. Some processors have special purpose modulo registers and addressing modes (such as bit reverse) that don't translate well into C, at least not without extending the language. Fixed point arithmatic operations are not supported in ANSI C either, but are a common feature on special purpose processors.
For low power/embedded applications, efficiency makes sense as well. Every CPU cycle wasted chips away at battery power. A more efficient algorithm means a smaller ROM size, and the CPU can either be clocked slower (can use cheaper memory and/or CPU) or put into a halted state when it isn't needed. (longer battery life) Coding small ISRs in assembly makes sense as well, as C compilers often must make worst case assumptions about saving processor context.
That being said, only a fool would try and re-write printf or cout in assembly, if they have a C/C++ compiler handy. Hand optimization is best used as a silver bullet, for the most computationally intensive or critical functions.
My rights don't need management.
While the majority of the Unreal engine is C++, we often write assembly-code versions of critical functions for specific platforms. Of course this is done after the C++ versions are tried and tested, and the bottlenecks are idetified.
To take full advantage of processor features like SSE or AltiVec you don't really have a choice.
For example, UT2004 contains SSE and AltiVec assembly versions of some of the vector and matrix manipulation functions, some of the visibility culling code, etc. The amount of work Dan Vogel put into this kind of optimization is one of the reasons that UT2004 runs better than UT2003 on the same hardware.
Learning assembly language is useful, as it's sometimes the right tool for the job.
Quoting: "the best implementations are written by those who've mastered assembly language".
I haven't read this book, but I'd hope that there would be some pretty good justification of the above statement. I suspect that it's not, though. First of all, who defines what the "best implementation" is?
As Knuth says, the first rule of program optimization is: "Don't do it". Trying to optimize a program when you're writing it leads to all sorts of problems including difficult to maintain code, increated time and budget required for the project, and often it's not even a hot spot anyway.
I used to be very concerned about using making my code fast, but have (over the decades) decided that making it obvious is much more important than speed, particularly in the initial implementation. Profiling allows you to concentrate on the 20% of the code that the program is actually spending 80% of it's time in, instead of guessing where the hot spots are going to be.
I've found that another benefit of using simpler code is that I'm more likely to throw away whole sections of simpler code and try radically different algorithms or mechanisms. More complicated code I find I'll try to just tweek instead of dumping wholesale. Randically different approaches can lead to 10x speedups where tweeks of existing code may give you 2x speedups, if you're lucky.
Don't get me wrong, I'm all for trying different approaches. I'm not sure I would have come to the same conclusion I have now if I hadn't spent quite a long time trying to write optimized code. It was a very different world back then, but I know I wasted a lot of time optimizing code that didn't at all need it. It was an experience though.
Sean
You, sir, are insane. Much of my job involves pushing around regular expressions and hash tables (aka associative arrays aka dictionaries). I know several flavors of assembler on distinct hardware platforms (x86, 68k, 6502, MIPS) so I say this out of experience rather than fear of the unknown: I'd rather swallow my own tongue than write anything non-trivial in a low-level language.
Seriously, a lot of people who know what they're doing have provided a huge library of functionality for me to pick and choose from. If I need to write a GUI app, I'll do it in Python with GTK or QT bindings. I am competent to build it in assembler, but why? It wouldn't be portable, it'd shave a very small amount of size from the end product (most of the project's resources are likely to be spent in the GUI libraries and not the core of the program), and would take 20 times longer than necessary.
There are a very few areas where low-level languages make sense. I haven't touched any of them in years.
Dewey, what part of this looks like authorities should be involved?
This guy says "Efficiency Is the Key". This guy is wrong.
With the incredible power provided to us by modern CPU's, efficiency is just about completely irrelevant for 99% of non-game applications. Think... when was the last time you thought "This word processor just doesn't respond to my keypresses fast enough." or "AIM takes way too long to open a new IM window."? The reason why these programs aren't getting "faster" (as the article complains) is because there is no way to do so. They spend 99.9% of their time waiting for user input already.
Optimizing code which doesn't need optimization is Bad with a capital 'B'. When optimizing code, there is almost always a tradeoff between efficiency and maintainability. Efficiency often requires cutting corners, killing opportunities for future expansion, or, at the very least, writing ugly code. When that added efficiency does not lead to any noticeable benefit to the user, why do it?
Now, granted, you shouldn't use an O(n) algorithm when an O(lg n) one exists to solve the same problem. However, knowing the difference between O(n) and O(lg n) has nothing to do with knowing assembly. The only benefits you can get out of knowing assembly are constant-multiplier speed increases. And, frankly, shaving off 50% of 0.1% CPU time used is not going to help much.
Really, the speed of modern CPU's is sickening. I can't count the number of times I've written a piece of code, thought "This is going to be so slow...", then watched it execute near instantaneously. Even when running programs in a prototype programming language I'm working on -- which currently runs about 40x slower than C, because it's a crappy prototype -- this happens to me regularly. The only time your code is going to be noticeably slow is if you are processing a very, very large data set or you are using slow algorithms. In the former case, sure, knowing assembly will help, but such cases are extremely rare in typical applications. In the latter case, find a better algorithm.
- He faults inefficient coding for the failure of software speed to keep up with CPU speed (or at least, its a "large part".) This is much less true than he lets on; Amdahl's Law means that the CPU is less and less responsible for the speed of an application, while things such as disk seek/transfer times, memory access times, and network latency all play huge roles in the speed of your computer's software.
- He seems to think that it's not terribly hard to become an "efficient" assembly language programmer. Bzzt, wrong! In the modern era of superscalar architectures, pipelining, processor specific instructions, branch delays, and memory heirarchies, it takes a hell of a lot of knowledge and experience to beat the performance of a good compiler.
- He apparently hasn't tried any large assembly language porting efforts lately. I'd love to see the effort involved in porting a large x86 assembly language program to a MIPS architecture, all the while maintaining that coveted "ultra-efficiency". The reality is that a good compiler can be reasonably efficient at porting a program to a new architecture, while a programmer usually isn't.
- He also apparently hasn't tried debugging a large chunk of assembly code lately. It is a fact of life that it is very difficult to debug assembly. By using a high-level language, you are increasing the readability of your software, which tends to decreases the number of bugs.
I could go on, but needless to say, I'm not impressed with the numerous assumptions and generalizations about assembly that he makes. Learning assembly will make your high-level programming better, and limited use of it can be appropriate, but using it all over the place is a huge mistake.
Having said that, knowing assembler is useful because it teaches you how the machine works.
However, most modern compilers can generate code that is much faster than handwritten assembler - especially because they know how to take advantage of the specialized processor architectures (hyper-threading, pipeling etc).
...richie - It is a good day to code.
One thing that many programmers take for granted these days is that compilers produce correct code nearly all the time. They've gotten really good over the years and are really a testament to the quality of compiler engineers. Even so...
I've been a programmer for over a decade and I've always found the worst problems to debug are when the problems aren't in your code but in the compiler. Compilers are programs too and have their own bugs. They aren't always 100% accurate at generating correct machine code for your source. And until the compiler gets fixed in the next patch or rev, you may be stuck with broken code unless you switch compilers.
Sometimes disassembly of the problem code and inlining correct assembly can be the difference between shipping a product or missing a deadline because you've spent months sitting around for the next compiler version to fix your problem for you.
ed
I didn't start programming until I was in my mid 20s (degree in Chemistry). I liked fiddling with Java but always felt uncomfortable about what was going on underneath the hood. So I took a few classes. The first was Computer Systems Architecture. We wrote a game in x86 assembler. That class completely opened up my understanding how programs actually worked. To understand the stack, the state machine nature of things, and memory was an awakening experience.
Now (~5yrs later) I'm a fully capable programmer and an even better designer. My preference is C, binary file formats, networking protocols, crafting elegant solutions for multiplexing IO. I'm lead on a project used in production by many companies large and small.
I genuinely feel assembler is a vital part of the learning process for a programmer.
An earlier poster mentioned how such a skill can help you find compiler bugs. This can be the case, but it is rare; I have located two such bugs in 20 years of programming. A more common use is to locate bugs in your code. When your brain refuses to see the missing braces around the wrongly indented code, or an spurious semicolon at the end of an if or while statement, reading the generated assembly code can save some extra hours of frustration. You will be able to see that the code the compiler generates differs from the code you think you wrote, and this will point you to the bug's location.
As I argue in Code Reading, other cases where reading assembly code can be of use are:
To read compiler-generated assembly code you need:
Obligatory "hello, world" program written in i386 assembly:
Diomidis Spinellis - #include "/dev/tty"