Ask HN: Why aren't there DSLs for Operating Systems? (Or are there?)
There are DSLs for nearly eveything we do with computers. Indeed, even "general purpose" programming languages are, in a sense, DSLs for ... math (Fortran), gofai (Lisp), etc. And of course there are zillions of more specific DSLs. The purpose of a DSL is to reduce the complexity of writing code for the target domain, which usually involves specialized vocabulary, functionality, and syntax. But the most complex programs that exist (well, at least among them) are operating systems. Yet we still build them in general purposes languages, like C. Of course, we almost immediately build a layer of functionality on the hardware and system services, but even when you get to the top, like programming bash commands, it's largely done in C (for Unix-likes). I'm wondering whether/why there isn't a DSL for operating systems. (Or maybe there is, but it's hard to find if so; I've never seen one, and it's a difficult set of phrases to search the web for, so I might be just missing the obvious, for which I apologize in advance, and appreciate the pointers.)
73 comments
[ 3.4 ms ] story [ 124 ms ] threadIn some sense C was the DSL to build UNIX. It becomming a general purpose language happened after that and because of the success of UNIX.
Also in general operating systems are extremely complex and need a wide range of functionality and extensibility while being able to easily interface with assembly. That makes a DSL tend towards a general purpose language, as has happened with C.
I think the question "is there a programming language made specifically for X?", is far less important than the question "is there a language in which I can do X, efficiently/securely/scalable/...?"
There are some languages which are clearly domain specific. Markdown is not a general computing language.
Note: That's avoid having to write os, interpreter, compiler, shell, etc 1st before writting application.
https://blog.lfe.io/excerpts/2015/03/27/1101-the-hidden-orig...
McCarthy was interested in computer intelligence, logic, and mathematics. Shaw, Newell, and Simon, at RAND and CIT, were already working on exactly these topics in their Logic Theorist project, using IPL, an ugly language that they designed, and ran on one the first digital computers, called JOHNNIAC - after John Von Neumann.
I you are interested in just how ugly IPL(V) was, you can see more of it than you'll ever want to here:
https://exhibits.stanford.edu/feigenbaum/catalog/ff363pt6522
Ugly as it may have been, IPL language did exactly what McCarthy wanted, and introduced the concepts of list processing, symbols, and recursion. But, a bit to your point, it's ugliness, being akin to assembly, was exceedingly off-putting.
A couple years later, at MIT, McCarthy (who was simultaneously and coincidentally playing around with lambda calculus) and his students (most centrally, Steve Russell) figured out how to do list processing etc in a much simpler syntax.
Still, the "modern" homoiconic Lisp of s-expressions was a bit farther down the line, as it was originally conceived with M-expressions, which were a bit more algol-like. S-expressions were initially just the data representation. Russell realized that the s-expression syntax could be used for both.
Thus the birth of Lisp, probably the world's most influential and enduring programming language. Sorry, this got a bit off topic.
AppleScript is a scripting language created by Apple. It allows users to directly control scriptable Macintosh applications, as well as parts of macOS itself. You can create scripts—sets of written instructions—to automate repetitive tasks, combine features from multiple scriptable applications, and create complex workflows.
That said, AppleScript is probably not long for this world. The future looks more like visual programming via Shortcuts.https://en.wikipedia.org/wiki/Domain-specific_language
Which, in an elegant self-own, you’re not going to tell us.
aka. typical DSL's at the pre-OS boot / bare metal level -> BIOS; communications protols - USB, epci, scsi; DSL on epci card, harddrive bios
DSL's used by OS -> ebpf, tcp, serial, printer drivers, display drivers (hdmi, displayport, vga)
DSL's allowing user to interact with OS -> shell, systemd
A DSL covering more and different parts of OS development would probably have to be so general that it doesn’t make sense not to use a general purpose language…
For Windows between 2000 and 7, that would be VBScript. The language itself is primitive, but through various COM APIs (WMI, ADSI, ADO, MSXML, WScript.Shell, etc.) one can do borderline anything with the OS, or even with the whole Windows networks.
Modern Windows, while still supporting VBScript and most of these COM things, has also added PowerShell as another option.
BTW, last couple times I dealt with Linux, I remember essential userland OS components implemented with bash scripts.
I have at the very least seen WSH support in glory days of ActivePerl, I think ActivePython and ActiveTCL included that as well. There was also I think a REXX implementation available.
Also, the same approach of using COM for everything is continued in PowerShell and generally all new Windows APIs - a lot of stuff in PowerShell is thin wrappers (if at all) over COM APIs, and you can definitely call custom COM objects as well.
There is so much bloat due to everyone making a DSL to learn distributed systems with, or every little bit of UNIX coming with its own text config format.
I’d like to get away from generating yaml for Docker and k8s and import balancing forks of microservice logic v8 style; read kernel telemetry from eBPF in the app to determine how many forks the code can add or needs to subtract, and terraform because it’s still just a Linux box under there.
But the cottage industry that profits from these ideas is threatened by these ideas and sticks with showing off a new arbitrary string parser that ALSO sends the strings to an API for you!
The software industry has turned into a jobs program and has little to do with novel engineering.
It would also eliminate who knows how many lines of code in the form of parsers/lexers for dozens of random static formats, and embedded HTTP clients that reach out to APIs being copy-pasted all over to handle ops.
It would bin a whole lot of cognitive gibberish that comes with Docker and k8s, and move SRE/ops thinking to leveraging the same language ecosystems as app developers, normalizing jargon.
But yeah let’s stick with your simple reduction. Apathy and lethargy are the zeitgeist of the day. The “disrupt!” industry has become a “wait not me though!” jobs program.
Effectively a government jobs program as the rate hikes forcing layoffs show. As soon as the Fed shut off the money printer, big techs house of cards started wobbling. Truly innovative measure like layoffs, a form of politically correct economic insecurity[1], not novel new ideas, was big techs reaction to government policy shift.
[1] https://www.nytimes.com/1997/02/27/business/job-insecurity-o...
The question "What is the domain specific language for operating sysyems?" is meaningless and unanswerable, because "operating systems" does not define the D in DSL in any meaningful useful way.
* For instance, when you try to replace all the sh scripts in a distro with say python (as some distros have tried to do) you immediately discover several ways that python is far less convenient for executing external executables and feeding, collecting, piping, their inputs and outputs. Then for all of the arcane annoyances with bash/ksh syntax, it's basic shell / batch / glue functionality is more important than all of it's "not like a better designed general purpose language" annoyances. In other words, exactly, it's not a general purpose language, it's a domain-specific language.
DSLs for interfacing with OSes exist in the form of command shells, syscalls, and ABIs.
EBNF is/was one way used to define how to write an OS.
This way different devices can use different procedures to, for example, put the device into sleep mode.
https://wiki.osdev.org/AML
Ansible, Puppet or Nix could also be viewed as operating system DSL. Again depending on what your goal is.
Widespread examples include firewalls and routing rules written in DSLs, which get compiled into a form that gets run inside the kernel. Example: nftables in Linux.
Some research OSes allow drivers to be written in a "safe" language to run inside the kernel. Some perform JIT-compilation, others create a custom kernel at compiled-time. Go search for Scout, Termite2, and Synthesis Kernel.
http://www.vpri.org/pdf/tr2012001_steps.pdf
[1] https://chreke.com/little-languages.html
[2] https://news.ycombinator.com/item?id=33693472
As others have pointed out, *nix systems (Linux in particular) are rife with DSLs. Not just C but (c|ba|k|tc|z)sh, sed, awk, grep, to name a few. Each of these tools has it's own mini DSL, some more complicated than others, that can than be composed to with other tools, using their own DSLs to manage tasks (e.g. operating system tasks).
Even the task of creating DSLs has many DSLs attached to it (lex, yacc, etc.).
Programs that get used and become popular introduce their own DSLs, often times. Apache, NGinx, etc. all have config files that each have their own special sauce of DSL for their own tasks.
Even many of the newer systems like Docker, Kubernetes, etc. have config files/DSLs to manage them.
I'm sure I'm forgetting even more.
You being the OP that you're referring to yourself in the third person? And you're trying to insinuate that I'm an idiot criticizing an expert? It'd be nice to say so instead of saying this so obliquely. I've insulted you. Sorry. I was and am arguing in good faith. Please show me the same courtesy.
It's great that you worked on all these assemblers, macro languages and operating systems but I stand by my point. There are many DSLs in and around "operating systems" that you've failed to identify.
Maybe the crux of disagreement is that you have in mind a particular type of DSL for a tranche of operating system engineering that you haven't properly articulated. Considering your oblique insult and response, I would guess this is the case.
I am currently interested in this problem and more specifically the expression problem.
Also the problem of how do you tell a computer to do X operation when it encounters Y.
Computers are often turning machines and state machines.
I recently implemented async/await with a giant switch statement.
Async await is far more powerful than bash jobs.
I think the scheduling of processes on a computer needs a powerful DSL.
Kubernetes is interesting since it scheduled processes on a cluster of nodes. But it doesn't define pipelines.
Kafka defines a pipeline for processing.
Bash defined pipelines of operations and processes text.
Java streams define a pipeline.
JavaScripts promises and C# async/await are interesting for scheduling tasks.
ETL workflows Extract Transform Load and Enterprise service buses often have visual DSL/GUIs with eclipse tools for defining mappings.
In Python I often chain together processes with POpen. But it's very low level
I think all these topics are linked.
I want a DSL for defining operations and chaining them together similar to a pipeline. I also want when_any and when_all support and multithreading support.
Writing this for each specific os / hardware situation (even in general case), would seem like a big waste of time vs. having the compiler generate it.
You can tell the compiler to do none of the standard bookkeeping (someone who actually writes OSes will probably correct me)
Is this an arguement that writting c to impliment awk, SQL, html/java script using raw X11 to input/output data is easier to do correctly / easier to understand / less buggy than just webassembly compiling gawk and use with standard web browswer features such as html/javascript etc.? Former C stuff is few million lines of code, later is less than a 1000. (including sql & database features in awk). ARC & icon language ports (5th generation programming languages), under a few hundred.
The arc & icon language ports would be smaller, but smaller code base means easier to add/impliment user requested features and still keep things 'small/understandable'.
Would much rather deal with under a few hundred than the equivalent few million lines of code.
Compiling for each possible OS / OS variation in order to run things to support the few hundred lines that actual do what interested in
or just the few hundred lines of code that actually do what interested in.
sbrk, registers and runtime stack are forms of memory management. (unix inodes via pipes, OS envirnment, and files)
If something were to offer a DSL for writing operating systems with, I think it would be either an embedded platform or a hypervisor.
DSLs for operating systems might be easier to write with programming languages that have higher-order unification – meaning that they can automatically piece together programs to fill out the meaning of one smaller word that has a complex, concise meaning – and totality checking, which means that given subprograms can be known to run to completion. And first-class types. (Dependently typed languages.)
This combination allows for tightly controlled and deterministic automation of programming, which is especially useful for getting rid of boilerplate code, conversion between formats, serialization and deserialization – and the maintenance of this kind of code… when all targets are moving targets due to many pieces of software that change from day to day. As found in things as complex and arbitrary as operating systems.
That said, various Lisp Machine systems as well as internals of Lisp implementations often contain DSL for implementing the OS/language, sometimes with many smaller DSLs (while the ur-example is "LOOP" macro from MIT, my favourite is a file from Genera bearing a comment - paraphrased - "behold, I implement half of PL/I to implement structure packing into byte vectors").
Of course, in languages like Lisp or TCL the separation between DSL and main language is not so stark as in case of DSLs implemented in let's say C or Java.
Looks like they released the compiler under the MIT license and put it on Github, so you may want to look into it.
https://en.wikipedia.org/wiki/P_(programming_language)
https://p-org.github.io/P/
https://www.microsoft.com/en-us/research/project/safe-asynch...
Compilers and manuals for these aren’t generally available, but here are published descriptions of two older variants, for use by customers who received source listings on microfiche:
http://www.bitsavers.org/pdf/ibm/360/pls/GC28-0786-0_Guide_t...
http://www.bitsavers.org/pdf/ibm/360/pls/GC28-6794-0_PLSIIgu...
* embedded os : https://blog.felgo.com/embedded/embedded-operating-systems
* OS modules / daemons : ebpf / systemd
* ebpf : https://news.ycombinator.com/item?id=33489935 ; https://news.ycombinator.com/item?id=33462031
* tiny core : https://en.wikipedia.org/wiki/Tiny_Core_Linux
* yocto : https://www.yoctoproject.org/
* 'bootloaders' don't have to just 'load an os' https://wiki.archlinux.org/title/syslinux
* uefi : https://askubuntu.com/questions/651902/what-is-the-differenc...
* OS device drivers for external devices such as printers (post script printers)
* OS api's