For years I have considered digging into what I consider "low level" languages. For me this means C and assembly. However I had no time for this yet, nor has it EVER been neccessary.

Now because I don't see any neccessity arising, I feel like I should either just schedule some point in time when I will study the subject or drop the plan forever.

My Position

For the past 4 years I have focused on "web technologies", which may change, and I am an application developer, which is unlikely to change.

In application development, I think usability is the most important thing. You write applications to be "consumed" by users. The more usable those applications are, the more value you have produced.

In order to achieve good usability, I believe the following things are viable

Good design: Well-thought-out features accessible through a well-thought-out user interface.

Correctness: The best design isn't worth anything, if not implemented correctly.

Flexibility: An application A should constantly evolve, so that its users need not switch to a different application B, that has new features, that A could implement. Applications addressing the same problem should not differ in features but in philosophy.

Performance: Performance contributes to a good user experience. An application is ideally always responsive and performs its tasks reasonably fast (based on their frequency). The value of performance optimization beyond the point where it is noticeable by the user is questionable.

I think low level programming is not going to help me with that, except for performance. But writing a whole app in a low level language for the sake of performance is premature optimization to me.

My Question

What could low level programming teach me, what other languages wouldn't teach me? Am I missing something, or is it just a skill, that is of very little use for application development? Please understand, that I am not questioning the value of C and assembly. It's just that in my everyday life, I am quite happy that all the intricacies of that world are abstracted away and managed for me (mostly by layers written in C/C++ and assembly themselves). I just don't see any concepts, that could be new to me, only details I would have to stuff my head with. So what's in it for me?

My Conclusion

Thanks to everyone for their answers. I must say, nobody really surprised me, but at least now I am quite sure I will drop this area of interest until any need for it arises.
To my understanding, writing assembly these days for processors as they are in use in today's CPUs is not only unneccesarily complicated, but risks to result in poorer runtime performance than a C counterpart. Optimizing by hand is nearly impossible due to OOE, while you do not get all kinds of optimizations a compiler can do automatically. Also, the code is either portable, because it uses a small subset of available commands, or it is optimized, but then it probably works on one architecture only.
Writing C is not nearly as neccessary anymore, as it was in the past. If I were to write an application in C, I would just as much use tested and established libraries and frameworks, that would spare me implementing string copy routines, sorting algorithms and other kind of stuff serving as exercise at university. My own code would execute faster at the cost of type safety. I am neither keen on reeinventing the wheel in the course of normal app development, nor trying to debug by looking at core dumps :D
I am currently experimenting with languages and interpreters, so if there is anything I would like to publish, I suppose I'd port a working concept to C, although C++ might just as well do the trick.
Again, thanks to everyone for your answers and your insight.

13 Answers
13

Low level programming is for the corner cases where there is a requirement not immediately present on normal desktop computers. This might be a speed bottleneck, or a memory bottleneck or something completely different, and it is very frequently very interesting to see what can be done given those requirements.

Think of it as Haikus or Limericks, where the restrictions make it interesting.

I think I'm really gonna go for "restrictions make it interesting". Of all the things mentioned here, this is probably the best. Back at school, I've been programming games on my calculator with 32kB memory and a 8Mhz CPU. It was fun, yet I didn't learn much I could benefit from now.
–
back2dosDec 16 '10 at 16:19

I was just thinking this recently. I'd currently consider myself as a C# developer - which is perfectly fine for my career.

However, every so often I miss out on the really low level things (essentially 'getting my hands dirty' by doing assembler or device drivers in C). I just miss the programming. I don't expect that to help me in my career massively. If device drivers or embedded systems are your thing, then it could help a lot.

The more I program in the abstracted languages, the more I miss what got me into computers in the first place: poking around the computer and seeing what twitches. Assembler and C are very much suited for poking :)

By using the older languages, I think you're forced to do pretty much everything yourself. In C# I can do something like myArray.SortBy(x=>x.Name). No way I'd be able to do that in C. I'm accepting that the language will do the best sorting for me. If I was to do it in C, I'd be able to go back to the days of my university modules and revise my different sort and search algorithms.

So, I think the lower level languages would help you to revise any of the long forgotten bits that have all being abstracted away. More of a personal challenge than a career progressing one.

+1 for voicing the love of poking about in the hardware and seeing what twitches - a true geek
–
Gary RoweNov 30 '10 at 13:03

1

You can write the sort function yourself in C# if you want. You can just as well use a library function to sort in in C if you want: gnu.org/s/libc/manual/html_node/Array-Sort-Function.html . I would even say by using older languages, you have to do less things yourself. Because most problems have already been solved. That doesn't prevent people from reinenting the wheel anyway :
–
back2dosNov 30 '10 at 16:33

My suggestion is to play around with C as an intellectual curiosity. Do not make a heavy time investment because it is not worth it.

Suggested goals:

Refresh your memory about the basic data structures and algorithms.

It is just some good thing to know, like algebra and geometry.

Try to do some college textbook exercises or program puzzles in C.

A better appreciation of the memory (bandwidth) hierarchy, all the way from the CPU cache to transoceanic network latency. This will help your application development skills at all levels.

Most importantly, it is good to learn about scenarios in which a small inconspicuous rearrangement of high-level code can result in a dramatic speed improvement.

Sometimes the reason can only be understood in the low-level implementation in the context of memory hierarchy.

Not understanding the natural cause of this possibility leads to ignorance, fear, and eventually to denial, thinking that it is wrong for high-level developers to tap into this kind of optimization. In reality there is nothing wrong with that.

Appreciate the aesthetics of component-based software systems, which enables low-level components developed in C/C++/Assembly to be used by high-level systems.

The aesthetics are exactly the same as software usability:

Good design (powerful, easy to use, well thought-out)

Correctness

Flexibility (extensions and new behaviors via composition of existing parts, each with a clearly-defined purpose)

Performance (without complicating the usability)

While you might not design your own low-level components, your understanding will help you evaluate and choose good components to use in your high-level projects.

Finally, appreciate that low-level components are almost always more complicated in their implementations, far from fathomable by just looking at the interface.

The low level is always complicated. A good library hides the complexity without diminishing its power.

Learn to read the "technical notes" written by component developers, which are suggestions to higher-level component users on how to best make use of the components.

C works almost as well. Most C concepts are easily translatable to machine language. Learn C and take a quick look at assembler, and you're in good shape.
–
David ThornleyNov 30 '10 at 15:07

I was about to post a similar answer. I'd argue that C also provides an appreciation for how the machine works, especially when managing memory is concerned. Additionally, many languages that abstract machine complexity are written in C. At least, the person would get a real understanding of just how pampered they are :)
–
Tim Post♦Nov 30 '10 at 15:09

If you don't do it just for fun, because geeks really love to have full control over their hardware, you might at least get a better feeling how much faster a program can become when written in C instead of, say, Java. You might also learn to really appreciate the features of higher-level languages, like garbage collection.

+1 for the geek fun. Although I must say, I am not much of a geek. And I hate hardware :)
–
back2dosNov 30 '10 at 12:41

1

The speed difference is usually irrelevant. This is especially true for web apps, where server-side processing is usually not the bottleneck.
–
David ThornleyNov 30 '10 at 15:05

David: I completely aggree for the average bread-and-butter web apps. In other domains, the difference can be very relevant.
–
user281377Nov 30 '10 at 15:10

1

@back2dos, if the idea of programming close to the hardware doesn't appeal to you, then I would say don't bother with it. It would be like forcing yourself to learn Latin just because it was the basis for a lot of later Romance languages.
–
tcrosleyNov 30 '10 at 23:22

2

given enough memory Java is as fast or faster than C.
–
user1249Dec 2 '10 at 17:32

Every programming language changes a little bit about how you think about programming in general. A concrete example I can give you is when I started to learn haskell and all of a sudden the functional bits of javascript, ruby, and python just made a whole lot more sense. I had never used foldl in any of my code before but after haskell I pretty much see it everywhere I see arrays. So chances are high that if you learn some C you will become much more aware of the relative performance characteristics of various constructs in your favorite language. A few minutes ago I was listening to a talk about writing speedy and optimized javascript and the speaker said "If it is hard to do in C then it will be really slow in javascript." His intent being that javascript is an interpreted language and the interpreter is either written in C or C++. This went right over my head because I have very little C experience and I have no idea what's hard or easy in C.

In a word, fun. When I used to play around with assembler (having worked down from VB to C++, C etc) it was just awesome to be moving data from one part of the processor to another. It was a great feeling to know exactly what was happening inside the CPU, with no worries about what was going on underneath which you didn't know about. Plus a great feeling of freedom - you can do just about anything, because there aren't inbuilt limitations which you find in higher level languages.

Also, being able to turn round to anyone who programmed in any other language whatsoever and go 'well, if you're not hardcore enough...' was childish, childish fun.

There actually is a lot going on inside the CPU that you do not see from assembler. Things like out-of-order execution, hyperthreading, and memory caching are being done by the CPU automatically. You can always go one step lower, until you reach the fundamental particles of matter. Or is matter just energy?
–
Kevin PankoDec 2 '10 at 16:54

One can avoid any such under-the-hood mystery by building their own CPU from transistors and logic chips :D (One of my favorite tech fantasies!) Anyway +1 for a great answer.
–
DarenWDec 2 '10 at 17:19

Fair point! Although when I last actually used assembler hyperthreading was probably more usually taken as referring to fast sewing, rather than CPUs...
–
Dan ODec 2 '10 at 20:15

It's very good to have some notion what's really going on at the lowest levels of a complex system, even if there's no logical need to know for one's everday duties. By far the best way to grok things at the bits level is build your own CPU. You have to think about machine language-level opcodes, understand why orthogonal instruction sets are so good, complications of interrupt handling, tradeoffs between complex circuits vs. microcode (e.g in multiplication units), and oh so much other fun!

But that, obviously, takes electronics know-how and is time consuming, so next best thing is toy around with an antique-style 8-bit CPU. Microcontrollers like the 8051 are still in widespread use and available to hobbyists. That still takes some know-how in herding electronics and making LEDs glow w/o smoking, and costs $$ if you're not already equiped for electronics.

Next best thing after that: toy around in a CPU simulator (emulator? I get those terms mixed up) -- these exist for Z80, 6502, 8086... all the old 8-bitters. That may be the most educational and fun for an applications programmer who doesn't know which end of the soldering iron to hold (though one learns that pretty fast :) How text is written to video memory, how assembly code tricks help with performance... there's plenty of fun stuff to explore at this level.

I'm not so sure about learning C as just another language, without some initial understanding of CPU inner workings. Knowing how bits are sent between CPU registers and how the memory accessed, helps tremendously with truly getting pointers and other C language concepts.

I am not so sure there are many high performance areas left. Gaming certainly doesn't require low level languages. For gaming, you usually use engines or at least you start with OpenGL or something. And for science parallelization is very important, and correctness. I suppose you'd be better off with OCaml or something. Performance critical areas are no longer those that crunch a lot of numbers, but that are used extremely frequently, such as kernels, drivers, storage engines and such. I guess less than 1% of all developers really ever touch those.
–
back2dosNov 30 '10 at 16:32

4

@back2dos, game engines dont just appear out of nowhere - someone has to write them. And what do you think OpenGL is written in? Not C#. One doesnt need to use low level languages for most applications these days ... but a lot of people work in the other areas that do require it.
–
GrandmasterBDec 2 '10 at 19:26

Is there any good reason to learn/practice low level programming. I have myself various answers depending on the context.

First, I am teaching C programming (but also OCaml and Java), motivating student to learn programming from the hard side is probably the hardest part of the task. The best argument I have found so far is "understanding": higher level languages hide a lot of underlying mechanisms and some times not for good, they also push you to stay in the higher level even when some low level tricks could really be useful (for performance, most of the time.) Understanding what you are using can really help using it better. My teaching experience prove me that students that have learn lower level programming (and other not user oriented, such compilers) are more adaptable and learn faster new higher level concepts or tools.

Second, as you state, performance is a part of the user experience. Most of the time, performance is seen as a matter of writing complex and near the machine code. This is not always the case, performance is much more a matter of algorithms and data structures but also interaction between algo and data. I use a special project on the subject, basically it is a simple path finding, but the real issue is the size of the data: the graph is infinite. The only way to achieve descent performances and to fit in memory is to write a dedicated memory allocator (in fact two, a pool allocator and recycling allocator.) This is something that you can't do in most higher level languages. In fact, most garbage-collected languages will have performance and memory issues.

There are probably a lot more arguments such as the stability (in the sense of history and longevity) of lower level languages against "hype" ones (the fact that a language considered as future reference for programming can disappear in a few years is a long story, one cannot predict the longevity of a new stuff, but this argument remains true for older languages ... ), of course there's also a matter of taste, or the fact that what can be done in most high level languages can also be done in lower level languages but not the other way round (but considering that, we should all code in assembly only ... )

I'm myself trap in both world (quite differently), I spend several years working on theoretical programming concept, type systems design and proof, and doing so I have only use and study very high level languages (mostly functional one, but also pure object oriented.) Recently I go back to the other side (mostly system and kernel programming) and found myself quite at ease in this area I'm having a lot of fun ! For me, the next step is to find the joint point: higher level language features for lower level programming ! So, far there's no language for that (perhaps google's go for userland system programming) and I am considering the idea of building my own language, but this is another story.

I think nowadays low and high level programming can be quite separated. Basically this means that you could live all your professional life without knowing C and assembler with no problems at all.
That said the C programming language cannot teach you a lot from programming and design points of view.

Just out of curiosity you could learn how things works in a lower level. When I was at University, for example, I enjoyed using gcc to generate assembler code from C++. It was useful to comprehend how polymorfism and exception are implemented. But apart from that the only things you could learn from C nowadays are:

1) dirty memory tricks. C is the best way to understand that there is no bottom down in programmers madness :)

2) GOTOs are actually used (and useful) to rollback errors

3) learn better how memory allocation works (difference between heap and stack anyone?).

So basically my thesis is: if you already finished University and you still don't need C, than don't learn it :)

You don't need to understand low level languages, but you should understand what is going on beneath the covers of your chosen high level language. Using a low level language will teach you this, but it's not the only way.

Here are some examples of low level concepts that can impact high level languages.

What could low level programming teach
me, what other languages wouldn't
teach me?

Most notably it will teach you how computers actually work. There is no other way of learning this than through low-level programming. No matter what kind of applications you program, this will always help. You will actually understand what's going on deep down beneath all that web stuff. And if you are working with Windows, the whole API is written in C, so knowing that language will make it possible for you to communicate directly with the OS, whenever you need to use a feature that your current languages and their libraries lack.

Of course low level programming will enable you to work with entirely different things, like embedded programming and realtime programming where asm/C/C++ is a must. If you have no interest in these kind of applications, there is indeed not much need to learn asm/C/C++.

Also, you will learn bits and bytes. Bit manipulations, hexadecimal etc. These things you may encounter now and then even when doing web/desktop programming. Encryption algorithms is one such example where it is used.