Why take a compiler course? (2010)
blog.regehr.org
blog.regehr.org
In my first job, back in the late 90s, I was working for a company that, having taken their biggest customer yet, had to split a very large C monolith into chunks that could run on separate servers. The architecture team of the company found all the places where the system should be cut, but that let them with hundreds of functions that had to be replaced with asynchronous calls relying on a queuing system. I was hired into the team that had to stub those hundreds of functions, type up serialization and deserialization for all the hundreds of data structures involved, and gluing it all together. So they had budgeted for 6 months of typing from a team of relatively new developers.
As you might expect, that's not how anyone wants their career to go, but I had taken the compiler class. So I knew I could parse all the header files for the functions we needed to replace, parse the data structures along with it, and just generate all the boilerplate away. My dev lead thought there's no way we could do this, but his manager decided that, at works, giving me two weeks to try it would be a great opportunity to teach the new hire the limit of his knowledge. But as anyone that has taken the compiler course knows, parsing boring C structs and header files isn't magic. So two weeks later, the project was done, and it was working.
As you might imagine, the dev lead, in his 40s, couldn't handle the results all that well, and left quickly. So I went from being stuck writing boilerplate from month to a quick promotion to team lead in under a quarter, all thanks to the compiler course.
I agree wholeheartedly. Knowledge, or even intelligence, shouldn't be the most highly valued skill in a team lead.
But there are many people extremely confident in their confirmation bias that seem to be unwilling to consider anything that might challenge their ideas. Our industry has a problem with celebrating the intelligent arsehole. Not only is humility not incentivized, it seems to be actively counterproductive.
I wonder how we can foster the kind of culture that values experience, encourages innovation, and is also able to get things done without chasing geese?
I think you're misinterpreting here. GP didn't make any generalizations about people in their 40's. They were providing additional context about a specific individual. Moreover, the context they were trying to convey was more about the delta in years of experience than a particular age bracket.
Also, thanks for the casual sarcasm, casual assumption of ill-will, casual tone policing of others according to your personal whims, casual accuse-first-rather-than-clarify and embarass-in-public-rather-than-confront-in-private approach. Really brightens the mood in here!
I have been in the situation where you can see even fresh to the workforce that everyone is doing something inefficiently. So you come up with an idea.
In my case it was more prosaic than compilers: they were assigning “pages” to devs to rewrite in .net, but clearly the pages had similarities and it made no sense for different people to be building the same thing in parallel their own way. I was simply suggesting to do some design worm upfront!
But it is hard to be listened to when either young or new to a company. Glad they have you a chance. Lesson for companies: give anyone passionate a chance to experiment!
Did you hand write a parser or does a library already exist ?
You'd think this is something more common with juniors than seniors, but in my experience it's been the opposite. Probably something about being distanced from the fundamentals made them forget how it's possible to build anything from scratch.
10 set i=1
20 i=i+1
20 print i, ". I will not chew gum in class"
30 if i<100 goto 20
40 exit
or something similar.Not a compiler, but how old am I?
The first thing I'd usually do when starting on a new architecture was write a disassembler. In the late 70s, I was mostly programming in 6809 assembly, usually in Microware's OS-9 operating system. Microware released a Pascal compiler, so I ran my disassembler over that. Turns out the compiler was self-hosting, written in Pascal, and the compiler output was almost completely unoptimized. So I decompiled the compiler back to Pascal by hand, just to see how it worked. I obviously had waaaaay more free-time back then.
I eventually read the green Dragon book (Aho & Ullman, Principles of Compiler Design), and ended up at Microsoft on the C/C++ team in 1991. Over the years, I've written several domain-specific languages (DSLs), small languages for some limited purpose. That early exposure to lexing, parsing, and error detection was invaluable.
I loved OS-9 on the 6809. It was my introduction into unix-ish-like systems that led into SunOS and later Linux and the foundations of my career.
If I can add any more info, let me know.
In that one year at NYU, I took two compiler courses, from RBK Dewar, of Spitbol and Ada fame. My specialty is not languages or compilers, but those courses were incredibly fascinating, and the exposure to the topics I learned has been useful throughout my career.
- I learned about lexing and parsing. I no longer remember the details of LALR, for example. But I understand the basic ideas well enough to construct lexing/parsing software whenever I need it, often using parser generator tools, but also rolling my own on occasion.
- I learned about code optimization, which is a fascinating topic. At the time, Dewar was working on SETL, a set-oriented language. And I remember the power of having sets as a builtin type, and how powerful that was for expressing flow analysis, for example. Those ideas combined nicely with what I later learned about relational algebra, and query optimization. (Codd's paper on the relational model was only seven years old when I started grad school!)
- Exposure to the ideas of interpreters and code generators, and even more fundamentally, the idea of code as a thing that can be manipulated programatically, has been useful throughout my career.
- Oh, and by the way, Dewar was a great teacher.
Oh, an lvalue is required? Since I now actually know WTF that means, I can deal with it.
It also cleared up a situation that had always confused the hell out of me: sometimes I'd compile and get 1 or 2 errors, so I'd make corrections and try compiling again, but then I'd get 8 or 10 errors! Seeing that whatever I did made everything much worse, I'd conclude those most not be the right corrections, and I'd feel lost and maybe even get stuck.
After taking compilers, I finally understood why: compilers have phases, and my corrections allowed the parsing phase to complete, which meant the semantic analysis phase could happen and give me errors. So for example, if I finally fix enough syntax errors that the compiler can tell I've written a function with some variables in it, then it can start giving me errors that they're not the right types.
That's not so much a compiler thing as it's a language thing. Perhaps even a C (and C++) language thing...
Understanding the lexer and the parser explains a lot of common errors (missing/ semicolon or curly bracket) and why they often point to errors in otherwise perfectly correct & unrelated code instead of their source location.
Understanding the compiler itself and how it operates over an AST means that if you get an error regarding a particular set of semantics, you can quickly learn what the implications are and how that maps to your code.
A good example (other than the GP's) is the massive, ugly template or overloading errors. They make sense and explain to you everything the compiler tried to do and how it failed each time it tried. The compiler doesn't know what is wrong and therefore doesn't have a more concise error to give you so it just tells you everything "it knows". From that you can work back and see where what you intended the code to do diverged from what the compiler thought the code did.
So it is a language thing but you build the intuition to pick up those language skills by learning/understanding compilers in general.
On one hand, they help you get things done. On the other, it can be _so_ hard to understand how things really work. Most programmers don't peel back too many layers, but that's okay.
If you're really interested, the Code book is fantastic in explaining how computers work: https://www.microsoftpressstore.com/store/code-the-hidden-la...
Combined with a proper OS class, it's the first time a student can truly understand all the levels of abstraction from the language to the logic gate.
And it also helps to recognize and solve parsing problems. How many programs end-up containing a parser, even if rudimentary, to read non-trivial input of perform validation? No, you can't use regex for that...
Compilers was the first (and, perhaps, only) course where having playid a lot worth computers before didn't matter. At. All.
At the same time, you learned some theory you didn't know (couldn't even have predicted) - that actually had direct practical application!
It was amazing and a microcosmos of CS - in that you first get a general understanding of the problem and desires outcome, learn theory that you couldn't have predicted but is amazingly apt for this, and end up making stuff work thanks to all of this.
It's an amazing experience that everyone with an interest in CS deserves to have.
1. Wrote a simulator of sorts for a 68xx CPU. User passed in assembly files and I simulated the execution and spat out cycle counts. The real-time application had a fixed time window it could not exceed. I did this in my first year out of college with compilers fresh on my mind.
2. Wrote an automated test tool for a proprietary protocol. The protocol had the usual opcodes but they could only be played in a certain order (cannot send B before C or can send B any number of times and have it be idempotent). The QA engineers were doing this by hand. I asked them if they could automated the test case generation and they looked at me as though I was an idiot. I developed a tool with its own simplified grammar that they could use to build test cases which exercised all combinations/permutations of the opcodes. Saved us a ton of time and made the developers more productive.
3. My hackiest project was an SGML parser that was used to generate hypertext documents. Tech writer wrote docs in FrameMaker. My hacky parser found the places where the TOC and the Index could be linked and inserted hypertext links. Net result is we had a document that could be printed and viewed online. Think 1993/1994.
I've sat with a number of engineers who thought the compiler was wrong and sat down and looked at the assembly with them and mapped it back to C only for them to realize the bug was in their code.
Compilers are fun. You should take a compiler course just for that!
- formal languages, Chomsky hiearchy and automata (DFAs, NFAs)
- algorithms & data structures (syntax trees, symbol tables & hashing)
- parsing algorithms
- asymptotic complexity (of automata recognition/acceptance and parsing algorithms)
- software architecture (single pass versus multi-pass, abstractions)
- operations research (graph coloring based register allocation)
- assembler & automatic code generation
- virtual machines & interpreters
It is a field where theory and practice come together beautifully (and works like the Aho et al. ¨Dragon Book¨ or Wirths ¨Compilers¨ are masterpieces that lucidly lay things out so after reading Chapter 2 of the former, or all of the latter short volume (barely 100 pages), a compiler is basically demystified to any undergrad).
Formal langs theory is too weird and formal
And dragon book is too focused on formal math
These books really only help you for the first five minutes of each part of a compiler e.g. "Here's how to write a register allocator, go find the calling convention yourself and my office hours are never"
For example, I once wrote a date/time "compiler" that could read dates and times in various human formats and construct a time_t from it. It's a giant mess if you approach it in an ad-hoc fashion. But if you approach it from a lexing then parsing standpoint, things work a lot better.
I see too many attempts at reading a textual data format that are done ad-hoc. Even worse are the attempts to design a data format where the designer clearly had no awareness of lexing and parsing - the format is just one ad-hoc kludge after another.
Compilers is one of the few topics that none of my colleagues seem care about, but IMHO it's so very important to learn how to do. In my Uni, the course only gets taught once every few years (it didn't help that our last department chair didn't care for the course at all and never scheduled it).
I count the day that I finished my LL(1) parser and lexer for my own compiler course as a student as the day I "earned" my chops.
Edit: Since there seems to be some discussion on this thread, I'll throw in the actual project that I gave my students (warts and all). https://github.com/agiacalone/cecs-444-semester-project
- La Guillotine
- Madame Defarge and friends
- etc.
from A Tale of Two Cities.
IIRC (may be wrong, read as a kid), those ladies used to signal which aristocrats should be chopped vs. not, by signalling with their knitting needles, or a nod or shake of the head, or some such - while sitting in the front row before the guillotine.
Ghoulish. Of course, as a kid, you (I) lap up and relish that stuff, like breakfast cereal.
Edit: Links:
https://en.m.wikipedia.org/wiki/Madame_Defarge
https://en.m.wikipedia.org/wiki/A_Tale_of_Two_Cities
Wow, I did not know before just now seeing the Wikipedia article above, that, to quote it:
[ As Dickens's best-known work of historical fiction, A Tale of Two Cities is said to be one of the best-selling novels of all time. ]
CS1311 - Data structures in pseudocode (or Scheme if you had the "X" class) CS1312 - Build the game "Risk" in Java CS2130 - Die a painful death at the hands of Jim Greenlee's compiler class.
It was interesting to see so many classmates panic in the class over how seemingly arbitrary the zeroes were given over minor mistakes. I, for example, was given a zero for a lab because I forgot to sign in. The grade for this lab was entirely based on signing in though because it was written incorrectly. The class just had tons of "life isn't fair, you should have paid attention" anecdotes.
But that's what us, software developers, relied to. No compiler means no app.
Which means some folks gotta maintain the GCC, Go, FPC, etc etc...
1. I had a whopping three weeks to prepare this course from scratch (welcome to Uni teaching) and it was what I could scrape together in that time.
2. Parsing is highly useful, and I felt my students could benefit from it.
3. It was what I did in undergrad.
4. It was not too difficult to accomplish, and a project like this can easily get out of hand for a semester project.
Once for a templating engine for SQL (taking values from the environment and using them queries). This was really nice for productivity and an intern could churn out dozens of reports a day. That was written with javacc.
Another time by using a parser (written with Antlr) to extract bits of PLSQL packages (procedures, functions) and move them from one environment to another without having to send the whole package.
Although this type of job is rare, it can be really useful when it shows up.
It's under the LLVM Foundation umbrella.
If you just want to deal with lexing, parsing, and interpretation (from scratch) for a reasonably complex class-based language, I recommend doing the (free) online book Crafting Interpreters.
The second half of that book re-implements the same language in C with garbage collection and a fast byte code interpreter.
Taking a four-day compiler course[1] (now five days) whetted my appetite for implementing languages and learning new ones, and led to a number of toy language projects. Also mentioned here, the book Crafting Interpreters is wonderful.
The world may not need many more programming languages, but making your own is a heck of a lot of fun. I find it especially satisfying when tests written in the new language start to surprise me by already passing, because enough of the language is working.
Regehr is right on the money here: parsers and interpreters are everywhere. Once you learn how approachable and applicable they are, you can solve problems faster and better.
I now always recommend to college interns that they take their CS department's compilers course their senior year (along with their English department's Shakespeare course).
You can run the code here:
https://replit.com/@Chronological/Compiler3
It's ~400 lines of code and it compiles the following AST
program = Main(
[
Assign("a", LiteralNumber(5)),
Assign("b", LiteralNumber(6)),
Println("Value is %d",
Mul(Add(Reference("a"), LiteralNumber(7)),
Add(LiteralNumber(8), Reference("b")))),
Println("Hello world %d", LiteralNumber(10))])
Or in other words, the following expression: a = 5
b = 6
(a + 7) * (8 + b)
If you run python3 main.py > assembly.S
gcc -o assembled assembly.S
./assembled
You should see Value is 168Hello world 10
It's barebones but I think it's the basis for a compiler.I’m a happy coder if I can translate my problem to a pipeline problem. Each pipeline step can be modelled as a pure function. Each artifact between each step can be inspected and cached. Pipeline failures can be resumed at the last valid artifact
On the other hand, the types of things we discussed in my algorithms course felt very hit-or-miss with regards to whether they actually felt useful or not. I'm not just talking about high-level abstractions that can miss important details in the real world like "memory can be accessed in constant time" either, but solving problems that were so contrived to the point of being almost implausible. The example I always remember is that in one of our problems sets, we were asked to write an algorithm that sorted an array of size N with each element within K indices of the correct sorted position in O(n*log(k)) time. I can't think of any situation where I'd have data so large with a small enough strict upper bound on K that such an algorithm would be necessary, but even if I did find myself in that situation, that's the exact type of input that the naive quicksort implementation would perform more efficiently on!
Maybe someday we'll have powerful enough tools that we can generate code that's performant without needing to do it ourselves, but at least for now, writing code that a computer executes efficiently is much easier when you actually understand what's being run on the computer and how it runs it, and a compilers course is a great way to start learning about the first half of that.
The usual advanced undergraduate / graduate level algorithms class is not supposed to teach you that. It's an introductory class to various techniques used in algorithm design and analysis, beyond those included in the undergraduate algorithms and data structures class.
Core algorithms classes then assume familiarity with those techniques. One of those core classes may be algorithm engineering, if your CS department has someone interested in the topic. And if the department assumes that there are enough students interested in it – the overlap between people interested in algorithms and software is often surprisingly small.
I feel like you're being a bit too pedantic here, because I don't really see how "learning various techniques used in algorithm design and analysis" doesn't somehow fall under the umbrella of "learning how to come up with efficient solutions to various problems"; an algorithm is certainly a solution to a certain type of problem, and efficiency is certainly a property that would be investigated as part of "algorithm analysis". Every single problem on our numerous homework sets and every question on every exam we had required us to design and then analyze our own algorithm for solving a problem presented to us, so it seems kind of silly to claim that we weren't supposed to be learning how to solve those problems, given that it's literally what they graded us on.
My best guess is that you objected to my characterization because you read it as a "why" rather than a "what". Whether the course was intended to teach us real-world skills or just try to teach the prerequisites needed for a career in algorithmic research doesn't really change the point I was trying to make, which was a potential answer to the question posed by the article, "Why take a compiler course?".
Some CS departments make the matter worse by calling the class Advanced Algorithms, which gives students a wrong impression. Students may believe that they are going to learn algorithms instead of tools for working with algorithms. I prefer the approach our mathematics department had when I was a student: they gave classes at the same level names like "Elements of Set Theory" and "Introduction to Elementary Number Theory".
Additionally, the example you used was actually pretty good. There is a parameter k that determines how easy or hard the specific instance is. The class used sorting as an example, because it's a non-trivial problem with many algorithms students are already familiar with. And the optimization target was asymptotic complexity, because it's easy to deal with without turning the assignment into a semester-long project.
If your job is designing practical algorithms (as mine is), you'll often end up in similar situations. Maybe you get the parameter k as a guarantee that allows you to use an algorithm that is faster with easy instances than the general-purpose algorithm. Or maybe you design an algorithm with its resource usage depending on k, regardless of the value. Or maybe the algorithm you already have is often faster than expected, and you want to find the parameters that determine how easy or hard an instance is. Or maybe you already have the algorithm and know the parameters, and you want to determine and log the values of the parameters in case a user reports worse than expected performance in some situations.
The article mentioned a very important but not well known aspect right at the end which is compilers is not a homogeneous topic but has a fairly independent parts. Front end, optimizers, and target code generation. I dabbled little bit in optimizers and a lot in target code generation. It was quite fun to figure out how to produce optimal machine instructions, or use as few registers as possible etc. Along the way I also got to learn a bit about the OS because one has to know an executable file’s layout, how to utilize heap, make sure not to over run stack etc.
And some fun algorithms too, such as a smart way to traverse tree by pointer reversal to avoid recursion as one can’t use recursion (extra space) while garbage collection.
1. If you are ever concerned with code performance, you need to know what the compiler (/interpreter) is doing with your code. With a compiler course, you'll get a basic understanding - enough to later actually look at what the compiler is doing with your real-life code.
2. If you write a software system which can handle computation tasks that are not fully known at compile-time - such as user queries in some domain-specific language - then you are likely to end up implementing a compiler in your software system. If you haven't learned about compilers, you'll (a.) may fail to realize that and (b.) are likely to do it more poorly than if you have.
---
My beef with compiler courses, though, is the excessive focus on parsing. Text parsing, look-ahead grammars etc may be interesting in themselves, but IMHO they're mostly self-contained and not what you will be concerned with in the life-scenarios I've described above. I would have liked, in hindsight, to have more time devoted to optimization selection, passes and what goes in each of them, optimization work on the AST vs work on the IR etc.
unfortunately there are too many people who think a CS curriculum should be an advanced coding bootcamp instead of a place where you actually explore how your software works
Learning them also teaches some skills on how to subdivide the solution to a really complex class of problems into comprehensible chunks.
Heck, there are many seemingly unrelated problem domains that can borrow solution strategies from compiler design and implementation.
It definitely is a nice tool to have in your tool belt.
The hardware stuff is in a simulator of course, but that doesn't take away from the gold mine of revelations one gains from going through this course.
The community is great as well, so many people did amazing things like build entire ray tracers in their own computer. Although I stopped at a sudoku game, seeing all of that is so good.
I went to a relatively small school in Canada, but they were very good about staying out of the way if you tried to take extra courses (with credit).
I STUPIDLY started going to lectures on Computer Systems this year without doing my research first (I couldn't find the timetable for Compilers, and relied on being able to take it officially next year). Turns out I don't have enough (or any) background in C, and so I couldn't make sense of a lot of the lecture material. Oh well, at least now I'm learning C, and I still have the lecture recordings.
Of course this overlaps strongly with particular aspects of compilers, but I find that external DSLs, which is where the overlap is greatest, are the tool that I reach for least often and that elicit the greatest resistance from fellow engineers.
Also for anyone. If you get a chance to take a linguistics course, take it. It really is a fascinating topic. The implications on computer languages, but just in general it is just interesting.
Studying compilers at university was highly beneficial. Before that course the code was a mess…
In a ring with a unit.
1/ there isn’t much to know about parsing and any good compiler course won’t spend too much time on it anyway
2/ and 3/ these points are not really about compilers in general and more about C compilers. You can also learn that trivia independently.
yes you should be able to "just do it" nothing involved is hard, everything i needed i had by age 14 in the 1990s without the internet. this means you have it too.
I'm interested in this topic, because I want to participate in TinyC compiler's development; I use it quite often to run C demos of mine and its execution is instant.
The least I can do is to either fix bugs or extend it to support more C99, C11, C17 features, and why not even C23 as soon as it gets approved?
All I need is to gain the necessary knowledge and experience to jump right in and start fixing things.