(2023-09-11) Where to move on from C? ------------------------------------- Not gonna lie, I love interpreted programming languages and became really good at several of them (like JS, Python or AWK, to name a few). But, of course, all those languages need some basis they themselves build upon: another class of languages which compiles to the native machine code. As of now, when we ask ourselves which language is this or that high-level runtime written in, we'll most probably find C, C++, Go or Rust. I also love pure ANSI C. Still not sure if I'm good at it but that definitely is my favorite "low-level" option of a natively compiled programming language. Or... was. You see, with C you get (almost) full control over your program's behavior, but this is the exact reason you just cannot fully focus on the logic you are trying to implement. I got away with it so many times (the most recent of them being Equi, NRJ16, LVTL-O and nne, of course) but when I implemented nntrac according to the original T-64 specification, this issue hit me as hard as it could. Yes, it fully conforms to the spec, but making it conform to the spec is only a half of work, and the other half is something I'm not even sure where to start: making it safe to use (e.g. not segfault on unbalanced parens and so on). Most probably, if/when this second half is done, the codebase SLOC count is going to increase x1.5 or even x2, and the actual processing logic may be even further removed from the original algorithm specified in the T-64 document. Just think about it: we already have SLOC overhead high enough just to make it stable and working according to the spec, but we have to add at least half of that amount to make it fully secure. Just because this is C. But what alternatives do we have in 2023 that I could really use as a C replacement for my own projects? Here, I'm going to do a (very) brief overview of ten programming languages I know at least something about that compile to native optimized machine code (no bytecode, bitcode or other VM-like runtime) and do have multiplatform/multiarchitecture support, with the "yes", "no" or "maybe" verdict at the beginning of each item. 1. C++. A big NO. It doesn't solve any real problem present with C but adds a whole lot of unnecessary complexity on top of it. I guess the fact that Linus Torvalds himself despises C++ is informative enough. 2. D. No. A sugarized (and no less complex) C++ derivative that didn't even bother removing those stupid mandatory semicolons and making functions first-class objects. 3. Pascal (family). No. By "family" I also meant Modula, Oberon-2 and so on, although Pascal itself is also still alive. A lot of syntactic overhead, mandatory semicolons, no way of doing FP either. 4. Go. Maybe. It (almost) does not have any bits that annoy me in other programming languages, besides having little type inference (you still have to write parameter types when declaring functions) and that pascaloid := operator (which you are not required to use though as x := ... is a syntactic sugar for var x = ...). It also does a good job at static linking. However, real-life code in Go often looks too verbose and begging to compact it a bit more, which is not possible in most cases. Overall, a good starting choice for your C replacement journey. The compiler package isn't so small though. 5. Rust. No. Just no. I see that code, it makes me go and wash my eyes, if not puke first. This language might be as safe, fast and powerful as they boast about it, but it's just extremely unpleasant to work with. This makes it a compiled cousin of Perl if you ask me. 6. Zig. No. Too many breaking changes even between minor versions, too many unnecessary syntactic features, and, as always, mandatory semicolons. The "zig cc" cross-compiler is beautiful though. They should focus on developing that part (especially when combined with the next language in this list) and drop their own language altogether. 7. Nim. Maybe (at least worth looking at), but most probably no. I like its expressiveness and a lot of features but, to be honest, we already have Python that enforces indentation. Besides, the compiler does not generate the machine code at once, it uses C (by default), C++, Objective-C or JS as the intermediate language and then delegates the remaining work to an external compiler. So, Nim is not as self-sufficient as the others in this list. Nevertheless, I'll give it a chance too. 8. Haskell. No, not really. The de-facto standard implementation, GHC (it's not GNU by the way, it's Glasgow), is too monstrous (larger than Go if you check) and the package system, Cabal, adds to this monstrosity even more. Not to mention the language itself is not very oriented at system programming. 9. OCaml. Maybe. In fact, this is the most likely candidate for me to switch to. The runtime is not as huge as Haskell's, its type inference is excellent, it has low-level data structures like "bytes" mutable type, and a nice machine-optimizing compiler. Besides, OCaml serves as an entry to other languages from ML family, ReasonML and SML being the most promising among others. 10. SBCL. No. I wish I could but if I wanted performance comparable with Java, I'd choose a language that would compile to JVM, such as Clojure. Too slow bro. Note that I didn't include Forth here because its major implementations that do have optimized compilers are quite different from one another in every aspect you can think of. Whether or not Forth can replace C, is a discussion for another time. I also didn't include Red as I don't consider it production ready yet. Of course when it becomes production ready, this will be a game changer, but for now, alas. So, here are my three favorites selected from the list: Go, Nim and OCaml. Being in a fair spot as I have zero experience with either of them yet, I'm going to answer the following questions for each of them (maybe not in this particular order) over the course of several following weeks: 1. How easy is it to write text processing CLI applications in this language? 2. How easy is it to write networking CLI applications in this language? 3. How easy is it to write GUI and/or Web applications in this language? 4. How easy is it to write and build mobile applications in this language? 5. How easy is it to retarget code in this language for different platforms? 6. Does this language allow to create fully static binaries? 7. How big of a performance overhead does this language create compared to C? Of course, all these questions can only be answered by practice. So, you get the idea what my several next posts are going to be about. --- Luxferre ---