I hope to start building a Lisp soon atop Mu. Maybe Arc? Maybe Wart? Maybe Bel? If the past is any guide it'll be a hybrid of several things. I'll probably also steal a few things from http://www.oilshell.org to try to make it ergonomic from the commandline.
SubX and Mu seem like pretty decent layers over machine code for systems programming, and I appreciate the transparency and control they offer.
How would you rate Mu as a systems programming language compared to say, Rust, for the purposes of implementing a language VM?
And what extensions do you expect to need before it is a good choice for such things?
Also, I'm somewhat curious about what you think about regarding applying SubX/Mu to cross-platform development. Clearly, that would be a challenge because the differences between platforms would be pretty hard to ignore in a transparent system. At the same time, it might be possible to build a code-generation framework on top of Mu that makes language and compiler development easier, because it has better access to the internals and have more control over what is produced on each platform.
Rust and Mu are similar in aiming for memory safety without garbage collection. They differ in how they go about it.
Rust provides better abstractions with higher performance and a more polished experience overall. It's also designed for concurrency. However, linear types are an adjustment, and the compiler is complex and (like other mainstream software) not really intended for users to understand the internals of.
Mu starts by encouraging people to understand it. I have no idea how far I can take it, so I err on the side of being simple to the point of simple-minded in service of an implementation that can fit in a single head. It doesn't require changing habits on memory management. It encourages less performant code (e.g. clearing a register often takes 5 bytes rather than 1 using an xor). It postpones thinking about memory in favor of memory leaks. It totally punts on concurrency for now.
Portability is another area of difference. Rust aims to be portable. Mu is tightly coupled with a single processor architecture (x86). I absolutely want to support other processors -- but they'll be in their own forks, so that each repo stays simple and people who don't run one processor don't have to think about it.
Concurrency is an interesting topic. I hadn't thought of that when reading about SubX, which mostly covered the part of assembly/machine language I'm familiar with. I always wished, though, that my assembly class (or an advanced sequel) had covered some of the more advanced topics for modern processors instead of the 8080, like how to set up memory management (the boot process on newer CPUs is rather involved...) and how multicore computation works. I know all about the higher-level implications, and can use threads etc., but have never actually learned how those things are handled at the bottom. Or syscalls etc.; I've only ever used them, not implemented them. That's a bit out of scope for the discussion, but something I look forward to "seeing-through" your future work on accessible internals. :)
I guess part of my curiosity was targetted at how you would build Mu up to handle performance and portability. Although the way they are usually implemented does obscure the internals, it seems possible that some compromise might be found. Any thoughts?
Perhaps the answer is at the higher lisp (AST / intermediate representation) level. Mu and SubX stay perfectly aligned to the final binary, but a code generator could optimize the AST and generate code in Mu for the target platform.
On that note, have you thought about giving them a more accessible API for such purposes? Or even just an s-expression syntax? Otherwise the target format for generation is limited to text, which would lose a lot of semantics in translation. Also, how are you thinking of maintaining introspection continuity across levels as you add more layers? Maybe something simple like source map support?
At the moment my ideas on all these areas are extremely hand-wavy. Ranging from "you don't really need it," to "somebody else's problem" :)
I feel fairly strongly that I don't want to add very many more layers. Ideally just one more. As more high-level languages get added, I want the lower levels to be integrated into Mu, so that they can in turn become the new HLL. But that's just an aspiration at this point.
One thing somebody else suggested was Plan9's assembly syntax. It may provide some inspiration for making SubX portable.