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.
The only downside is the stdlib being as fast-moving of a target as it is. Right now I've had to put a pin on getting panic stack traces to work on my N64 code because apparently the upcoming release changes a bunch of stuff around panic/stacktrace handling (and it's already changed quite a bit over the years even before these new changes).
The fact that zig can compile C code makes it useful for other languages too. I recently started using `zig cc` to cross-compile Nim for lots of different platforms within the same environment.
It takes no time to setup and, honestly, works like magic.
Agree, C interop is IMHO the big feature of Zig. There are plenty of systems programming languages in 2025, but where Zig shines is its pragmatism: a single standalone binary containing compiler, libc, build system, code formatter and test runner for C and Zig.
As of late though, I've been concerned with some "holy wars"/"ideological postures" that the dev team started which IMHO departs from the original "let's be pragmatic" mantra.
- There's a bunch of places where the stdlib just crashes on unreachable assertions, and that won't be fixed "because the kernel should have better error reporting".
- There are a bunch of kernel syscalls which are just not possible to call "because C enums should not allow aliases"
- etc
I hope this trend fades away and it gets back on a more pragmatic stance on these issues, nobody wants a systems programming language that plays the programming police.
Otherwise, C3 looks promising as well (though not as nice than Zig IMHO), but currently it's a bit too barebone to my taste. There no stable LSP, no nvim plug-in, etc.
Instead of "cross-compiling" or just running a native perl interpreter (there's one for about every platform!), I prefer how Actually Portable Executables make Perl multiplatform with just 1 binary asset running everywhere!
I wanted to write a webserver processing CGI to learn more about the "old school web", so I wrote https://github.com/csdvrx/PerlPleBean and the simplicity of just downloading and running the .com on anything is very nice
I'm now trying to do the same in Python3, but it's not as fun - and I'm not yet to the part where I will try to safely run python code within the python webserver, either through restrictedpython or ast.parse(), ast.walk(), eval(compile()) ...
Ah that's an interesting take, my opinion is that the stdlib doesn't move fast enough.
In its current state it's pretty broken, most of the "process", "os" and "posix" modules are either straight up raising unreachable in normal scenarios, or simply badly designed. I would like the stdlib to be much more fast moving and fix all these issues, but I had the impression most work on it is frozen until 0.15 or 0.16, after incremental compilation is done.
Sadly the job market looks dead
You can make your own though :)
Right now it's just a bunch of WIP Zig interfaces for the N64's hardware, but the end-goal is to get it developed enough for homebrew gamedev.
To get there, though, I need to implement Zig-ish interfaces to the N64's hardware, which is slowly-but-surely happening at https://fsl.yellowapple.us/zig64/dir?ci=trunk
Things I like:
- Vendor libraries like Raylib and MicroUI make it easy to get started
- I can pass around memory allocators and loggers implicitly using context, or explicitly if I need to.
- natively supports vector math and swizzling
- error handling with `or_else` and `or_return`
Things I don't like:
- Name spacing is a bit annoying. The convention is to prefix the procedures but I don't like how they look. It really isn't a big issue.
Have a quick read of the overview and if you are still interested, I highly recommand 'Understanding the Odin Programming Language' book by Karl Zylinski [2]
[1] https://odin-lang.org/docs/overview/
[2] https://odinbook.com/
Regardless, I do recommend people to try it out. I use Linux and OpenBSD, too, despite Linus and Theo. :)
[1] The reason for why I think this can be found in their pull requests, but it's been some time I think.
The compiler is very fast, even over large codebases.
Mostly trying to bring AWS tooling to the platform[1], or experimenting with cross-compilation[2] using another less well known systems language, zig.
[1] https://github.com/chris-armstrong/smaws/ [2] https://github.com/chris-armstrong/opam-cross-lambda
Re: AWS tooling, have you seen https://github.com/solvuu/awsm ?
It generates code for all 300+ AWS services and produces both Async and Lwt forms. Should be fairly extensible to Eio.
I worked on this. Let me know if you want to tag team.
The syntax is also not very friendly IMO. It's a shame because it has a lot of great ideas and a nice type system without getting all monad in your face. I think with better tooling and friendlier syntax it could have been a lot more popular. Too late for that though; it's going to stay consigned to Jane Street and maybe some compilers. Everyone else will use Rust and deal with the much worse compile time.
Very true. There's an alternate syntax for OCaml called "ReasonML" that looks much more, uh, reasonable: https://reasonml.github.io/
They exist, I think you just mean `int` is 63-bit and you need to use operators specialized `Int64.t` for the full precision.
Why do you think that the syntax is not very friendly?
Not saying you are wrong, just interested to know.
https://dev.realworldocaml.org/
I also saw this book OCaml from the Very Beginning by John Whitington.
https://ocaml-book.com/
I have not read that one yet. But I know about the author, from having come across his PDF tools written in OCaml, called CamlPDF, earlier.
https://github.com/johnwhitington/camlpdf
>CamlPDF is an OCaml library for reading, writing and modifying PDF files. It is the basis of the "CPDF" command line tool and C/C++/Java/Python/.NET/JavaScript API, which is available at http://www.coherentpdf.com/.
Symbolic debugger seem to be going out of fashion
Being a huge fan of F# v2 who has ditched all MS products, I didn't think OCaml was able to be systems-level because its integer vars can't be precisely specified.
I'd love to know if I'm wrong about this. Anyone?
You also mention that Int32 and Int64 are recent, however these libraries were part of OCaml already in the 4.X versions of the compiler and standard library (now we are in the 5.3).
Note that in OCaml you can use C libraries and it is quite common to manage Int32, Int64, signed etc...
What does that mean?
In the 1980s, complete workstations were written in Lisp down to the lowest level code. With garbage collection of course. Operating system written in Lisp, application software written in Lisp, etc.
Symbolics Lisp Machine
https://www.chai.uni-hamburg.de/~moeller/symbolics-info/fami...
LMI Lambda http://images.computerhistory.org/revonline/images/500004885...
We're talking about commercial, production-quality, expensive machines. These machines had important software like 3D design software, CAD/CAM software, etc. And very, very advanced OS. You could inspect (step into) a function, then into the standard library, and then you could keep stepping into and into until you ended up looking at the operating system code.
The OS code, being dynamically linked, could be changed at runtime.
If you want something that is essentially just a modernized C, go with Zig. The concept of compile-time programming having the same appearance as runtime programming is very cool in my opinion. My only major complaint at the moment is that duck typing is fairly prevalent. Sometimes function arguments are declared `anytype` and you occasionally have to dive down multiple function calls to figure out what's going on, though that's not too much of a hindrance in practice, in my experience.
My personal favorite language is Nim. Efficient, but simple, memory management (drawing from C++/Rust). You rarely have to think too hard about it, yet making fast programs is not complicated. You can stick to the stack when you want to. The flexibility at compile-time gives you great power (but it requires great responsibility -- easy to abuse in a bad way). The type system is awesome. The only downside for me is the tooling. The LSP needs much optimization, for example.
Also, I believe high-level compiled languages suffer from the fact that it is very hard to tell which construct is expensive and which is a zero-cost abstraction. Rust has the same issue, but "zero-cost" is a major feature of the language so you don't feel bad using an Iterator, for example, in kernel code. With Nim it is hard to tell.
https://tour.dlang.org/tour/en/gems/compile-time-function-ev...
You mean, something that Lisp does since the early 1980s?
Um, no. Debugging a macro in Lisp is a terrible experience while debugging a comptime function in Zig is brain dead simple.
Zig is the first "macro" system I've used that doesn't want to make me blow my brains out when I need to debug it.
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.
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 have also moved back hard to using TCL as my scripting language. I like it too much, and bouncing between Python, Go, and such for DevOps glue tires me out.
For systems, I love using plan9 (9front) to solve problems, which grounds me to C, awk, sed, and the rc shell.
A few decades ago plenty of Oberon dialects.
As language geek, I randomly select languages when doing hobby coding.
Regarding Go's remark, even if I dislike Go's authors decisions, back in my day writing compilers, linkers, firmware, networking stacks, and OS services was considered systems programming.
Likewise .NET team has been making wonders catching up to what C# 1.0 should have been for low level code, given its Delphi linage.
Java, in the context of being whole Android userspace, including drivers, there is very little systems exposed in the NDK. Vulkan is one of the few things not exposed to Java land, and that is being fixed with WebGPU like API in an upcoming version.
Discarding the preprocessor and replacing it with a proper module system is huge. I got burnt by templates and horrifying compile times in C++, but haven't had any problems with D templates. The module system makes templates feel much more natural to use. The syntax for templates is a huge improvement, and throwing `static if` into the mix results in concise and easy-to-read code.
I also quickly realized (with the help of some people on the D discord) that the garbage collector is fine for my needs. So I don't have to spend any time thinking about memory management... put stuff on the stack when I can for speed, othrewise just GC and don't think about it. I think there may be some issue with multithreading and the GC, but this is supposed to get fixed with the new GC that's on the way.
There are a few other nice QOL improvements. Getting rid of `->` is honestly worth its weight in gold. There's nothing difficult about forgetting to change a `.` to a `->` or vice versa in C++, but not having to trip over it periodically when you're compiling makes the language that much smoother. I was also initially confused by the `inout` keyword but have come to really like that, as well. Little niceties like `const(T[])` are small but, again, reducing just a little bit of friction like this across the language makes D much, much more pleasant to deal with than C++.
I think the main challenge the language is facing right now is that it's huge and a lot of it is still getting worked out. I never thought I'd pine for C++'s "rule of 3/5/0", but it's a lot tighter and more logically consistent than the equivalent in D. But part of that is there being a huge community of C++ developers who have taken the time to promulgate rules of thumb in the community. I'd kill for an "Effective D" book to short circuit some of this process... after all, I'm trying to write code, not play at the margins, tinkering with D's idiosyncracies.
So far in converting the lexer it does make it more comprehensible, it will probably do the same for the parser and AST. The real interesting bit will be once I tackle the later stages.
Deleted Comment
Also on a more serious note: I started some projects in Zig and even though most of my future projects will be built on a bedrock of C code, more and more of the top-level layers will happen in Zig.
https://github.com/codr7/eli
What I love most about C is the fact that it doesn't talk down to me no matter what crazy ideas I come up with. It's therapeutic for me, reminds me why I started writing code in the first place.
I realize that's also what many hate about it, the fact that it gives other people freedoms they would never trust themselves with.
For the latter example, one could theoretically avoid declaring the variables 'event' an 'rg_match', instead direcly including the compound literals in the respective function calls. However it is a question of taste, and what is more readable.
(The above have designated initialisers, I'm can't remember if there are any compound literal examples there.
There is however one here, when the BSTR_K macro is also expanded, also the earlier BSTR_INIT:
I do use those so thank you :)