(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 ---