Ask HN: What less-popular systems programming language are you using?
Less popular or less commonly used ones.
By that, I mean, not including the usual suspects, such as C, C++, Rust and Go (I know the controversy about the last one being a systems programming language or not).
I'm asking this because I used C for both application programming and systems programming, early in my career, before I moved to using other languages such as Java and Python.
And of late, I've been wanting to get back to doing some systems programming, but preferably in a more modern language (than C) which is meant for that.
461 comments
[ 2.7 ms ] story [ 366 ms ] threadDid you ever check out Eiffel for systems programming work?
I had been checking it out some years ago, and apart from the general points about it, one use of it that I found interesting was in an article about using it for creating HP printer drivers. The author had mentioned some concrete benefits that they found from using it for that purpose.
Edit: I searched for that article, and found it:
Eiffel for embedded systems at Hewlett-Packard:
https://archive.eiffel.com/eiffel/projects/hp/creel.html
from the Wikipedia article about Fortran, under the Science and Engineering section:
https://en.m.wikipedia.org/wiki/Fortran
Although a 1968 journal article by the authors of BASIC already described FORTRAN as "old-fashioned",[58] programs have been written in Fortran for many decades and there is a vast body of Fortran software in daily use throughout the scientific and engineering communities.[59] Jay Pasachoff wrote in 1984 that "physics and astronomy students simply have to learn FORTRAN. So much exists in FORTRAN that it seems unlikely that scientists will change to Pascal, Modula-2, or whatever."[60] In 1993, Cecil E. Leith called FORTRAN the "mother tongue of scientific computing", adding that its replacement by any other possible language "may remain a forlorn hope".[61]
It is the primary language for some of the most intensive super-computing tasks, such as in astronomy, climate modeling, computational chemistry, computational economics, computational fluid dynamics, computational physics, data analysis,[62] hydrological modeling, numerical linear algebra and numerical libraries (LAPACK, IMSL and NAG), optimization, satellite simulation, structural engineering, and weather prediction.[63] Many of the floating-point benchmarks to gauge the performance of new computer processors, such as the floating-point components of the SPEC benchmarks (e.g., CFP2006, CFP2017) are written in Fortran. Math algorithms are well documented in Numerical Recipes.
That didn't age well.
My professor working on control system analysis for electrical power grids later thought that if he were to write it today, it would likely be done in matlab.
Despite its history it is a pretty modern language if you enable all warnings, set implicit none and ignore the old style of coding (a la FORTRAN 77 of older).
I had read about him and about his FP language early in my career, when I was reading up on all kinds of computer subjects.
https://en.m.wikipedia.org/wiki/John_Backus
https://en.m.wikipedia.org/wiki/Function-level_programming
https://en.m.wikipedia.org/wiki/FP_(programming_language)
[0] https://en.wikipedia.org/wiki/PRIMOS
[1] https://en.wikipedia.org/wiki/Livermore_Time_Sharing_System
[2] https://webhome.weizmann.ac.il/home/fhlevins/RTF/RTF-TOC.htm...
The open source tooling has significantly improved since I started using it in the last five years.
Idk, if someone just reinvents clean C without the nonsense garbage with some modules and package manager this will be a huge win. Let me access my null pointers, let me leak memory, just get the hell out of my way and let me program and hold my hand only where I want it to be held - sane types that give me refactoring, code completion and code understanding, modules with imports. Let compiler give sane error messages instead of this cryptic c++ garbage. Is this too much to ask?
So, if only there is std with implicit allocators?
I wouldn't mind a "better C" that could use an LLM for static code analysis while I was coding. I.e. be more strict about typing, perhaps. Get out of my way, but please inform me if I need more coffee.
1 - https://dlang.org/spec/betterc.html
- It becomes impossible to call the wrong deallocation procedure.
- Deallocation can happen when the type (or allocator) goes out of scope, preventing dangling pointers as you can't have a pointer type in scope when the original type is out of scope.
This probably goes against Zig's design goal of making everything explicit, but I think that they take that too far in many ways.
A fairly common pattern in the Zig stdlib and my own code is to pass the allocator to the `init` function of a struct.
If what you mean is that allocation should be internal to the type, I don't agree with that. I much prefer having explicit control over allocation and deallocation.
The stdlib GPA for example is pretty slow, so I often prefer to use an alternative allocator such as an arena backed by a page allocator. For a CLI program that runs and then exits, this is perfect.
Separating interface and implementation is a good thing, but often you just want to split things into separate files without separate compilation. C supports #include and so it is maximally flexible.
Theres also D but finding libraries for whatever I want to work on proves problematic at times as well.
The biggest thing to be added recently is GPU programming, which given Mojo's focus on ML/AI makes a lot of sense.
It's probably not the best language to look into for general purpose systems programming, but if you are going to be interacting with GPUs or other hardware then maybe it's good to give it a look.
It is still changing a lot, so no real stability yet, but to be expected for such a young language.
[1] https://docs.modular.com/mojo/changelog/
https://www.google.com/search?q=perl+simple+things+easy+and+...
That said, the edges are still (very) rough when it comes to tooling (generics and macros absolutely murder Nimsuggest/lsp) and also "invisible" things impacting performance such as defect handling (--panics:on) and the way the different memory management schemes introduce different types of overhead even when working with purely stack allocated data.
But even with all that it's still an extremely pleasant and performant language to work with (when writing single threaded programs at least)
For parallel programming, there are also handy libraries. The best of which is Weave[1], but Malebolgia[2] is authored by the creator of Nim and works well in its own way too.
There is also active work being done on a new implementation of Nim which intends to clean up the some of the long-term spaghetti that the current implementation has turned into (like most long-term projects do), called Nimony[3], and is also led by the original creator of Nim. It is years away from production according to him, but is at least in the works.
I'd have to say Nim is by far my favorite programming language. The terseness, flexibility, and high performance, make it feel almost sci-fi to me. My only major complaint currently is the tooling, but even the tooling is still adequate. I'm glad it exists. Highly recommend.
[1] https://github.com/mratsim/weave
[2] https://github.com/Araq/malebolgia
[3] https://github.com/nim-lang/nimony
But ultimately I realized that I’m not writing the type of software which requires such strict verification. If I was writing an internet protocol or something like that, I may reach for it again.
Currently solo managing a 30k line data analysis application I built for my company. Easily fits in my head given the obvious pyramidal functional-like structure. Maybe two lines of memory semantics anywhere in the entire thing, and only one module that's OO with a constrained scope. Lots of static data files (style sheets, fonts) slurped up as const strings at compile time. Incredible performance. Invoked by our PHP server backend, so instead of doing parallel or async in the analysis, the server gets that through batch invocation.
Working stupid well for our product, plus I can easily compile binaries that run on ARM and RISC-V chips for our embedded team just by invoking the proper gcc backend.
Replaced an ailing and deliberately obfuscated 20 year old jumble of C and PHP designed to extort an IP settlement from my company. Did it in a year.
1 - https://github.com/treeform/hobby
Agreed. Good IDE support can easily add explicit types too.
Admittedly, the slowness of the compiler (due to the nature of the language), and lack of better tooling are not helping, but 9 out of 10 times I enjoy way more writing Crystal than Go.
gen servers, everywhere.
A non-answer, but tangentially relevant:
I once fiddled with Forth, but never actually accomplished anything with it.
Several OSs are written in Lisp; in some of them the difference between OS and application is a bit vague. At the time none of them were available to me to play with.
I discovered Oberon and fell in love. My first real programming language was Pascal, and Oberon is part of the same family. Oberon consisted of a compiler, operating system, user interface, application software, and tools, all self-hosted on Oberon. There was even an Oberon CPU at one time. But Oberon turned out to be just an academic curiosity, and wasn't available for any hardware I had access to anyway.
Turbo Assembler FTW :)
I personally don't think programming paradigms like OOP, procedural or functional make anything easier/harder necessarily, just talking QoL stuff.
And obviously "easy" is relative: Odin is still a low level language where you need to manage your own memory.
https://lwn.net/Articles/1006117/
It’s not always clear what is meant by “system programming”. I’ve begun writing utility scripts in Julia; it’s practical now because the startup time is vastly improved. These can be run like bash scripts, with a shebang line that invokes Julia with the desired environment (using the --project flag).
I think it is clear enough. The language must have a small or non-existing runtime so it is practical to write systems that do not ship the same fat runtime on every binary. The language must support compiling to binaries, otherwise it really cannot be used by itself for systems. It must provide access to the available Operating System API directly without the need for bindings (to the extent possible, as some OSs only expose the C API;ABI).
What is a system, you may ask. I think you can define that as anything that can run by itself (no runtime) and perform any "low level" operation permitted by the OS.
there was some Russian dev running a systems tech company, I forget his name, living in Thailand, like in koh samui or similar place. he used D for his work, which was software products. came across him on the net. I saw a couple of his posts about D.
one was titled, why D, and the other was, D as a scripting language.
I thought both were good.
I did, a quick thought, regarding https://github.com/docandrew/SPARKTLS: you might find https://github.com/Componolit/libsparkcrypto useful, too, if you have not already.
Nice projects BTW!
Desktop apps: definitely. There's bindings for various UI toolkits like GTK and I know of a few people working on games in Ada, usually thick bindings like SDL: https://github.com/ada-game-framework and https://www.youtube.com/playlist?list=PLn3eTxaOtL2Oxl9HbNOhI... There's also Gnoga, which is similar to Electron for writing UI apps: https://github.com/Blady-Com/gnoga
A bunch of libraries for various drivers or other useful things on https://alire.ada.dev/crates.html (to include something like "ada_gui" in your ada project, you would just use alire, e.g. `alr with ada_gui`).
Much of Ada's webapp functionality is either interfacing with the Ada Web Server or gnoga (I've written a few servers using Ada Web Server, including one for an ".io" game).
There's an LLVM compiler which in theory can produce wasm but I've not messed with it: https://github.com/AdaCore/gnat-llvm
Mobile platforms can be targetted and cross-compiled in Alire, but I'm not sure who's doing it right now.
For anyone interested, I definitely recommend checking out some of the presentations of Ada's recent FOSDEM dev room https://fosdem.org/2025/schedule/track/ada/
There are fewer, and they do tend to be more demanding, but they certainly exist.
https://funcui.avaloniaui.net
https://github.com/fabulous-dev/Fabulous
(I'm sure there are more, these two are those which I could recall from the top off my head)
* Span<T>: https://learn.microsoft.com/en-us/archive/msdn-magazine/2018...
* C# now has a limited borrow checker-like mechanism to safely handle local references: https://em-tg.github.io/csborrow/
* Here is a series of articles on the topic: https://www.stevejgordon.co.uk/writing-high-performance-csha...
* In general, avoid enterprise style C# (ie., lots of class and design patterns) and features like LINQ which allocate a lot of temporaries.
Then why would they add Span<T>, SIMD types and overhaul ref types in the first place?
If you link an example snippet of the type of code that gave you pause, I’m sure there is a better and more idiomatic way to write it.
C# is Java-but-with-lessons-learnt, and is significantly less verbose and "enterprisey" in typical usage.
Modern .NET 9 especially embraces compile-time code generation, a "minimal" style, and relatively high performance code compared to Java.
Even if the JVM is faster in benchmarks for hot loops, typical Java code has far more ceremony and overhead compared to typical C# code.
Can you give an example? I don't think this is true anymore for modern Java (Java 21+)
Java currently beats .NET by about 40%: https://www.techempower.com/benchmarks/#hw=ph&test=fortune&s...
I judge more idiomatic / typical code complexity by the length of stack traces in production web app crashes. Enterprise Java apps can produce monstrous traces that are tens of pages long.
ASP.NET Core 9 is a bit worse than ASP.NET Web Forms used to be because of the increased flexibility and async capability, but it's still nowhere near as bad as a typical Java app.
In terms of code length / abstraction nonsense overhead, have a look at the new Minimal APIs for how lightweight code can get in modern C# web apps: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...
What matters in practical scenarios is that ASP.NET Core is significantly faster than Spring Boot. If you have a team willing to use ActiveJ or Vert.x, you are just as likely have a team willing to customize their C# implementation to produce numbers just as good at web application tasks and much better at something lower level. There are also issues with TechEmpower that make it highly sensitive to specific HW/Kernel/Libraries combination in ways which alter the rankings significantly. .NET team hosts a farm to do their own TechEmpower runs and it just keeps regressing with each new version of Linux kernel (for all entries), despite CPU% going down and throughput improving in separate more isolated ASP.NET Core evaluations. Mind you, the architecture of ASP.NET Core + Kestrel, in my opinion, leaves some performance on the table, and I think Techempower is a decent demonstration of where you can expect the average framework performance to sit at once you start looking at specific popular options most teams use.
https://openjdk.org/jeps/401
Smaller objects from dropping identity is nice but it really doesn't seem like it gives you more explicit memory layout, lifecycle, c interop etc that C# has with their structs. Maybe I'm missing something.
Also can recommend reading all the performance improvements blog posts by Stephen Toub as well as learning to understand disassembly at a basic level which .NET offers a few convenient tools to get access to.
Helped me a bunch to get Sharpl spinning, much appreciated.
https://github.com/codr7/sharpl
That is if you don't want to get into unsafe code.
Apart from that (which simply concerns strings, as they're the great source of performance issues, all generic best practices, applicable to any language, should be followed.
There are plenty resources on the net, just search for it.
Embedded is diverse. I would not use .NET for small embedded, i.e. stuff running on Arduino or ESP32.
However, I have successfully used .NET runtime in production for embedded software running on top of more performant SoCs, like 4 ARMv7 cores, couple GB RAM, Linux kernel. The software still has large pieces written in C and C++ (e.g. NanoVG rendering library) but all higher-level stuff like networking, file handling, and GUI are in memory-safe C#.
[1] https://nanoframework.net/ [2] https://gocosmos.org/
You should also pour one out for Longhorn, where internal politics tanked the idea, and eventually Windows team redid all those .NET based ideas into COM/C++, and were even proud of doing so (see Hilo sample documentation), hence why nowadays COM based libraries are the main way to expose modern Windows APIs (aka post Windows XP).
Had they collaborated instead, probably Windows would be closer to something like Android userspace nowadays.
Or for Ironclad, another one from Microsoft research, lesser known, also from the same research group, which even includes type safe Assembly,
https://www.microsoft.com/en-us/research/publication/safe-to...
Microsoft Research has plenty of work in such domains, they also had a LLVM like compiler framework, based on MSIL, called Phoenix, among other stuff, e.g. Dafny, FStar, Drawbridge, also come from OS projects.
Unfortunely classical Microsoft management has been more like it isn't Windows, it isn't shipping.
Nokia owns the shambling corpse that is Bell Labs. Looking beyond the English speaking world, I wouldn’t discount that the chaebols (LG, Samsung, Mitsubishi, etc) all have a few companies dedicated to research at the Bell Labs level.
https://learn.microsoft.com/en-us/archive/msdn-magazine/2015...
https://www.ghielectronics.com/netmf/
https://www.ghielectronics.com/sitcore/
https://www.wildernesslabs.co/
I've been having a lot of fun with Java lately, the maturity of the language/implementation and libraries allows me to focus on the actual problem I'm solving in ways no other language can currently match.
https://github.com/codr7/tyred-java https://github.com/codr7/eli-java
The big take-away I got from this (admittedly quite old now) experiment is that getting advertised performance out of unmanaged languages for typical real-world (i.e., non-benchmark) tasks often requires a lot more care than people really account for. Nowadays memory dominates performance more so than CPU, and the combination of a JIT compiler and a good generational, compacting garbage collector - like C# and Java developers typically enjoy - often does a better job of turning idiomatic, non-hand-optimized code into something that minimizes walks of shame to the RAM chips.
Sure these days not many folks write OS kernel in Pascal, but there are some, e.g: https://github.com/torokernel/torokernel
I once want to try Forth (perhaps there's a Unix clone in Forth?), but seems like most folks using it are embedded/hardware devs.
“The Macintosh used the same Motorola 68000 microprocessor as its predecessor, the Lisa, and we wanted to leverage as much code written for Lisa as we could. But most of the Lisa code was written in the Pascal programming language. Since the Macintosh had much tighter memory constraints, we needed to write most of our system-oriented code in the most efficient way possible, using the native language of the processor, 68000 assembly language. Even so, we could still use Lisa code by hand translating the Pascal into assembly language.”
MacOS was clearly Pascal-oriented, with its ‘Str255’, ‘Str63’, etc. data types.
even early Windows versions were somewhat Pascal-oriented, with things like "long far pascal" used in C function declarations, to indicate the calling convention being used, whether right to left, or left to right, iirc.
source: C language developers for the Macintosh OS
1. It has an actually sound type system.
2. The language and standard library are waaaaaaaay ahead of Javascript.
3. The tooling is top notch. Better than JS/TS.
But on the other hand:
4. Way smaller ecosystem.
5. Debugging is worse if you're compiling to JS. The fact that the code you run is basically identical to the code you write in TS can be a big advantage. Only really applies for web pages though.
6. Type unions are way nicer in TS.
7. Non-nullable types interact badly with classes. It can make writing methods correctly really awkward - you have to explicitly copy member variables to locals, modify them and then write them back.
8. Way smaller community.
I know you didn't ask me but I think that not ensuring soudness is a feature because it allows the type system to wrap something that could work without it. Would you like unit tests if removing them would break your code? Maybe it's not a fair comparison, or maybe it is...
But when the types are sound you can use them to compile better code. That's what most languages with "proper" static types (not just type hints) do.
You can use other libraries for this like Riverpod with flutter_hooks and functional_widget which essentially removes the OOP structure of widgets and turns them more into functions, in a way.
I was reading another post about someone showing some AI stuff and then: https://news.ycombinator.com/item?id=43246127