From 7a088d67394afd972286a02ac3afbdcbed83780c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 31 Dec 2025 21:27:55 -0800 Subject: [PATCH] Edit, finish, and publish post on PL Signed-off-by: Danila Fedorin --- .../i_love_programming_languages/index.md | 149 +++++++++++++++++- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/content/blog/i_love_programming_languages/index.md b/content/blog/i_love_programming_languages/index.md index 1d8ff04..05df9db 100644 --- a/content/blog/i_love_programming_languages/index.md +++ b/content/blog/i_love_programming_languages/index.md @@ -1,7 +1,6 @@ --- title: "Reasons to Love the Field of Programming Languages" -date: 2025-12-06T18:08:24-08:00 -draft: true +date: 2025-12-31 tags: ["Programming Languages", "Compilers", "Type Systems"] --- @@ -18,6 +17,8 @@ theorists to developers to laypeople. So, in that spirit, I am writing this list as a non-exhaustive survey that holds the dual purpose of explaining my personal infatuation with PL, and providing others with ways to engage with PL that align with their existing interests. +I try to provide rationale for each claim, but you can just read the reasons +themselves and skip the rest. My general thesis goes something like this: programming languages are a unique mix of the __inherently human and social__ and the __deeply mathematical__, @@ -169,7 +170,7 @@ They are rooted not only in pragmatic concerns of "what can I do with these transistors?", but in the deeper questions of "what can be done with a computer?". -* __Reason 7__: programming languages are built on foundations of computation, +* __Reason 7__: general-purpose programming languages are built on foundations of computation, and wield the power to compute anything we consider "effectively computable at all". Because of these mathematical beginnings, we have long had precise and powerful @@ -216,7 +217,8 @@ spite of Rice's theorem. Much of the time, too, we can do so in a way that is straightforward for humans to understand and machines to execute. * __Reason 9__: in the face of the fundamentally impossible, type systems - grant us confidence in our programs for surprisingly little conceptual cost. + pragmatically grant us confidence in our programs for surprisingly little + conceptual cost. At first, type systems look like engineering formalisms. That may well be the original intention, but in our invention of type systems, @@ -251,7 +253,7 @@ I therefore present: {{< details summary="Bonus meta-reason to love the mathy side of PL!" >}} In addition to the theoretical depth, I also find great enjoyment in the way that PL is practiced. -Here more than elsewhere, the creativity and artfulness I've mentioned before come into +Here more than elsewhere, creativity and artfulness come into play. In PL, [inference rules](https://en.wikipedia.org/wiki/Rule_of_inference) are a lingua franca through which the formalisms I've mentioned above are expressed and shared. They are such a central tool in the field that I've @@ -274,3 +276,140 @@ PL. for expressing its formalisms, which precisely highlights core concepts and leaves room for creative expression and elegance. {{< /details >}} + +I know that mathematics is a polarizing subject. Often, I find myself +torn between wanting precision and eschewing overzealous formalism. The +cusp between the two is probably determined by my own tolerance for abstraction. +Regardless of how much abstraction you are interested in learning about, +PL has another dimension, close to the ground: more often than not, our languages +need to execute on real hardware. + +### Pragmatics of PL + +Your perfectly-designed language can be completely useless if there is no +way to +{{< sidenote "right" "execute-note" "execute it" >}} +Technically, there are language that don't care if you execute them at all. +Many programs in theorem-proving languages like Agda and Rocq exist only +to be type-checked. So, you could nitpick this claim; or, you could take +it more generally: your language can be useless if there's no +way to make it efficiently do what it's been made to do. +{{< /sidenote >}} efficiently. Thus, the field of PL subsumes not only +the theoretical foundations of languages and their human-centric design; it +includes also their realization as software. + +The overall point of this section is that there is much depth to the techniques +involved in bringing a programming language to life. If you are a tinkerer +or engineer at heart, you will never run out of avenues of exploration. +The reasons are all framed from this perspective. + +One fascinating aspect to programming languages is the "direction" from +which they have grown. On one side, you have languages that came +together from the need to control and describe hardware. I'd say that +this is the case for C and C++, Fortran, and others. More often than not, +these languages are compiled to machine code. Still subject to human +constraints, these languages often evolve more user-facing features as time +goes on. On the other side, you have languages developed to enable +people to write software, later faced constraints of actually working +efficiently. These are languages like Python, Ruby, and JavaScript. These +languages are often interpreted (executed by a dedicated program), with +techniques such as [just-in-time compilation](https://en.wikipedia.org/wiki/Just-in-time_compilation). +There is no one-size-fits-all way to execute a language, and as a result, + +* __Reason 11__: the techniques of executing programming languages are varied + and rich. From compilation, to JIT, to interpretation, the field + has many sub-disciplines, each with its own know-hows and tricks. + +At the same time, someone whose goal is to actually develop a compiler +likely doesn't want to develop everything from scratch. To do so would +be a daunting task, especially if you want the compiler to run beyond +the confines of a personal machine. CPU [architectures](https://en.wikipedia.org/wiki/Instruction_set_architecture) +and operating system differences are hard for any individual to keep up with. +Fortunately, we have a gargantuan ongoing effort in the field: +the [LLVM Project](https://llvm.org/). LLVM spans numerous architectures +and targets, and has become a common back-end for languages like C++ +(via [Clang](https://clang.llvm.org/get_started.html)), Swift, and Rust. +LLVM helps share and distribute the load of keeping up with the ongoing +march of architectures and OSes. It also provides a shared playground upon +which to experiment with language implementations, optimizations, and more. + +* __Reason 12__: large projects like LLVM enable language designers to + lean on decades of precedent to develop a compiler for their language. + +Though LLVM is powerful, it does not automatically grant languages implemented +with it good performance. In fact, no other tool does. To make a language +run fast requires a deep understanding of the language itself, the hardware +upon which it runs, and the tools used to execute it. That is a big ask! +Modern computers are extraordinarily complex. Techniques such as +[out-of-order execution](https://en.wikipedia.org/wiki/Out-of-order_execution), +[caching](https://en.wikipedia.org/wiki/Cache_(computing)#HARDWARE), +and [speculative execution](https://en.wikipedia.org/wiki/Speculative_execution) +are constantly at play. This means that any program is subject to hard-to-predict +and often unintuitive effects. On top of that, depending on your language's +capabilities, performance work can often entail working with additional +hardware, such as GPUs and NICs, which have their own distinct performance +characteristics. This applies both to compiled and interpreted languages. +Therefore, I give you: + +* __Reason 13__: improving the performance of a programming language is rife + with opportunities to engage with low-level details of the hardware + and operating system. + +In the [mathematics section](#the-mathematics-of-pl), we talked about how constructing correct +optimizations requires an understanding of the language's semantics. It +was one of the practical uses for having a mathematical definition of a language. +Reason 13 is where that comes in, but the synthesis is not automatic. In fact, +a discipline sits in-between defining how a language behaves and +optimizing programs: program analysis. Algorithms that analyze +properties of programs such as [reaching definitions](https://en.wikipedia.org/wiki/Reaching_definition) +enable optimizations such as [loop-invariant code motion](https://en.wikipedia.org/wiki/Loop-invariant_code_motion), +which can have very significant performance impact. At the same time, for an +analysis to be correct, it must be grounded in the program's mathematical +semantics. There are many fascinating techniques in this discipline, +including [ones that use lattice theory](https://cs.au.dk/~amoeller/spa/spa.pdf). + +* __Reason 14__: the sub-discipline of program analysis serves as a grounded + application of PL theory to PL practice, enabling numerous optimizations + and transformations. + +The programs your compiler generates are software, and, as we just saw, +may need to be tweaked for performance. But the compiler and/or interpreter +is itself a piece of software, and its own performance. Today's language +implementations are subject to demands that hadn't been there historically. +For instance, languages are used to provide [language servers](https://microsoft.github.io/language-server-protocol/) +to enable editors to give users deeper insights into their code. Today, +a language implementation may be called upon every keystroke to provide +a typing user live updates. This has led to the introduction of +techniques like the [query architecture](https://ollef.github.io/blog/posts/query-based-compilers.html) +(see also [salsa](https://github.com/salsa-rs/salsa)) to avoid +redundant work and re-used intermediate results. New language implementations +like that of [Carbon](https://github.com/carbon-language/carbon-lang) +are exploring alternative representations of programs in memory. In +short, + +* __Reason 15__: language implementations are themselves pieces of software, + subject to unique constraints and requiring careful and innovative + engineering. + +### Conclusion + +I've now given a tour of ways in which I found the PL field compelling, +organized across three broad categories. There is just one more reason +I'd like to share. + +I was 16 years old when I got involved with the world of programming +languages and compilers. Though I made efforts to learn about it through +literature (the _Dragon Book_, and _Modern Compiler Design_), I simply +didn't have the background to find these resources accessible. However, all +was not lost. The PL community online has been, and still is, a vibrant and +enthusiastic place. I have found it to be welcoming of folks with backgrounds +spanning complete beginners and experts alike. Back then, it gave me +accessible introductions to anything I wanted. Now, every week I see new +articles go by that challenge my intuitions, teach me new things, or take PL +ideas to absurd and humorous extremes. So, my final reason: + +* __Reason 16__: the programming languages community is full of brilliant, + kind, welcoming and enthusiastic people, who dedicate much of their + time to spreading the joy of the field. + + I ❤️ you.